unique_sdk 0.9.38__tar.gz → 0.9.39__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.38 → unique_sdk-0.9.39}/CHANGELOG.md +3 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/PKG-INFO +220 -172
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/README.md +216 -171
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/pyproject.toml +1 -1
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/__init__.py +1 -0
- unique_sdk-0.9.39/unique_sdk/api_resources/_space.py +144 -0
- unique_sdk-0.9.39/unique_sdk/utils/chat_in_space.py +53 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/LICENSE +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/_api_requestor.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/_api_resource.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/_api_version.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/_error.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/_http_client.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/_list_object.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/_object_classes.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/_request_options.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/_unique_object.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/_unique_ql.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/_unique_response.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/_util.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/_version.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/_webhook.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/api_resources/__init__.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/api_resources/_acronyms.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/api_resources/_chat_completion.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/api_resources/_content.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/api_resources/_embedding.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/api_resources/_event.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/api_resources/_folder.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/api_resources/_integrated.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/api_resources/_message.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/api_resources/_message_assessment.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/api_resources/_search.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/api_resources/_search_string.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/api_resources/_short_term_memory.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/utils/chat_history.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/utils/file_io.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/utils/sources.py +0 -0
- {unique_sdk-0.9.38 → unique_sdk-0.9.39}/unique_sdk/utils/token.py +0 -0
|
@@ -5,6 +5,9 @@ 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.39] - 2025-07-18
|
|
9
|
+
- Add script to chat in a space.
|
|
10
|
+
|
|
8
11
|
## [0.9.38] - 2025-07-18
|
|
9
12
|
- [Experimental] Add support for Unique OpenAI proxy. You can now use the OpenAI SDK directly through Unique. Checkout how to do this and a few examples here: `tutorials/unique_basics/sdk_examples/openai_scripts.py`.
|
|
10
13
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: unique_sdk
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.39
|
|
4
4
|
Summary:
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Martin Fadler
|
|
@@ -28,7 +28,6 @@ The Unique Python SDK provides access to the public API of Unique FinanceGPT. It
|
|
|
28
28
|
4. [Webhook Triggers](#webhook-triggers)
|
|
29
29
|
5. [Available API Resources](#available-api-resources)
|
|
30
30
|
- [Content](#content)
|
|
31
|
-
- [Folder](#folder)
|
|
32
31
|
- [Message](#message)
|
|
33
32
|
- [Chat Completion](#chat-completion)
|
|
34
33
|
- [Embeddings](#embeddings)
|
|
@@ -46,6 +45,7 @@ The Unique Python SDK provides access to the public API of Unique FinanceGPT. It
|
|
|
46
45
|
- [File Io](#file-io)
|
|
47
46
|
- [Sources](#sources)
|
|
48
47
|
- [token](#token)
|
|
48
|
+
- [Chat In Space](#chat-in-space)
|
|
49
49
|
8. [Error Handling](#error-handling)
|
|
50
50
|
9. [Examples](#examples)
|
|
51
51
|
|
|
@@ -244,8 +244,12 @@ unique_sdk.Message.modify(
|
|
|
244
244
|
- [Content](#content)
|
|
245
245
|
- [Message](#message)
|
|
246
246
|
- [Chat Completion](#chat-completion)
|
|
247
|
+
- [Embeddings](#embeddings)
|
|
248
|
+
- [Acronyms](#acronyms)
|
|
247
249
|
- [Search](#search)
|
|
248
250
|
- [Search String](#search-string)
|
|
251
|
+
- [Short Term Memory](#short-term-memory)
|
|
252
|
+
- [Message Assessment](#message-assessment)
|
|
249
253
|
- [Folder](#folder)
|
|
250
254
|
|
|
251
255
|
Most of the API services provide an asynchronous version of the method. The async methods are suffixed with `_async`.
|
|
@@ -469,175 +473,6 @@ Allows you to ingest a magic table sheet, each row is processed and converted in
|
|
|
469
473
|
unique_sdk.Content.ingest_magic_table_sheets(**params)
|
|
470
474
|
```
|
|
471
475
|
|
|
472
|
-
### Folder
|
|
473
|
-
|
|
474
|
-
#### `unique_sdk.Folder.get`
|
|
475
|
-
|
|
476
|
-
Get a folder by scope id or by path.
|
|
477
|
-
|
|
478
|
-
By scope id:
|
|
479
|
-
|
|
480
|
-
```python
|
|
481
|
-
unique_sdk.Folder.get_info(
|
|
482
|
-
user_id=user_id,
|
|
483
|
-
company_id=company_id,
|
|
484
|
-
scopeId="scope_w78wfn114va9o22s13r03yq",
|
|
485
|
-
)
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
By path:
|
|
489
|
-
|
|
490
|
-
```python
|
|
491
|
-
unique_sdk.Folder.get_info(
|
|
492
|
-
user_id=user_id,
|
|
493
|
-
company_id=company_id,
|
|
494
|
-
folderPath="/Company/Atlas/Due Dilligence/Arch,
|
|
495
|
-
)
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
#### `unique_sdk.Folder.create_paths`
|
|
499
|
-
|
|
500
|
-
Create each folder in the provided list of paths if it does not already exist.
|
|
501
|
-
|
|
502
|
-
```python
|
|
503
|
-
unique_sdk.Folder.create_paths(
|
|
504
|
-
user_id=user_id,
|
|
505
|
-
company_id=company_id,
|
|
506
|
-
paths=["/unique/path1", "/unique/path2"],
|
|
507
|
-
)
|
|
508
|
-
```
|
|
509
|
-
|
|
510
|
-
#### `unique_sdk.Folder.update_ingestion_config`
|
|
511
|
-
|
|
512
|
-
Allows you to update the ingestion config of a folder and choose whether to apply to the subscopes or not: `
|
|
513
|
-
|
|
514
|
-
- `ingestionConfig`
|
|
515
|
-
- `applyToSubScopes`
|
|
516
|
-
|
|
517
|
-
The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
|
|
518
|
-
|
|
519
|
-
Example of updating the ingestion config of a folder and its subfolders using the id.
|
|
520
|
-
|
|
521
|
-
```python
|
|
522
|
-
unique_sdk.Folder.update_ingestion_config(
|
|
523
|
-
user_id=user_id,
|
|
524
|
-
company_id=company_id,
|
|
525
|
-
scopeId="scope_qbnkde820dbmuw2900,
|
|
526
|
-
ingestionConfig={
|
|
527
|
-
"chunkStrategy": "default",
|
|
528
|
-
"uniqueIngestionMode": "standard",
|
|
529
|
-
},
|
|
530
|
-
applyToSubScopes=True
|
|
531
|
-
)
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
Example of updating the ingestion config of a folder and its subfolders using the path.
|
|
535
|
-
|
|
536
|
-
```python
|
|
537
|
-
unique_sdk.Folder.update_ingestion_config(
|
|
538
|
-
user_id=user_id,
|
|
539
|
-
company_id=company_id,
|
|
540
|
-
folderPath="/Company/folder1/folder2",
|
|
541
|
-
ingestionConfig={
|
|
542
|
-
"chunkStrategy": "default",
|
|
543
|
-
"uniqueIngestionMode": "standard",
|
|
544
|
-
},
|
|
545
|
-
applyToSubScopes=True
|
|
546
|
-
)
|
|
547
|
-
```
|
|
548
|
-
|
|
549
|
-
#### `unique_sdk.Folder.add_access`
|
|
550
|
-
|
|
551
|
-
Allows you to add access to a folder and apply to the subfolders or not: `
|
|
552
|
-
|
|
553
|
-
- `scopeAccesses`
|
|
554
|
-
- `applyToSubScopes`
|
|
555
|
-
|
|
556
|
-
The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
|
|
557
|
-
|
|
558
|
-
Example of adding access to a folder and its subfolders using the id.
|
|
559
|
-
|
|
560
|
-
```python
|
|
561
|
-
unique_sdk.Folder.add_access(
|
|
562
|
-
user_id=user_id,
|
|
563
|
-
company_id=company_id,
|
|
564
|
-
scopeId="scope_231e4kjn4foffww34",
|
|
565
|
-
scopeAccesses=[
|
|
566
|
-
{
|
|
567
|
-
"entityId": "group_id",
|
|
568
|
-
"type": "WRITE",
|
|
569
|
-
"entityType": "GROUP",
|
|
570
|
-
}
|
|
571
|
-
],
|
|
572
|
-
applyToSubScopes=True,
|
|
573
|
-
)
|
|
574
|
-
```
|
|
575
|
-
|
|
576
|
-
Example of adding access to a folder and its subfolders using the folder path.
|
|
577
|
-
|
|
578
|
-
```python
|
|
579
|
-
unique_sdk.Folder.add_access(
|
|
580
|
-
user_id=user_id,
|
|
581
|
-
company_id=company_id,
|
|
582
|
-
folderPath="/Company/folder1/folder2"
|
|
583
|
-
scopeAccesses=[
|
|
584
|
-
{
|
|
585
|
-
"entityId": "group_id",
|
|
586
|
-
"type": "WRITE",
|
|
587
|
-
"entityType": "GROUP",
|
|
588
|
-
}
|
|
589
|
-
],
|
|
590
|
-
applyToSubScopes=True,
|
|
591
|
-
)
|
|
592
|
-
```
|
|
593
|
-
|
|
594
|
-
#### `unique_sdk.Folder.remove_access`
|
|
595
|
-
|
|
596
|
-
Allows you to delete access from a folder and apply to the subfolders or not: `
|
|
597
|
-
|
|
598
|
-
- `scopeAccesses`
|
|
599
|
-
- `applyToSubScopes`
|
|
600
|
-
|
|
601
|
-
The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
Example of deleting the access from a folder and its subfolders using the id.
|
|
605
|
-
|
|
606
|
-
```python
|
|
607
|
-
unique_sdk.Folder.remove_access(
|
|
608
|
-
user_id=user_id,
|
|
609
|
-
company_id=company_id,
|
|
610
|
-
scopeId="scope_dwekjnf3330woioppm,
|
|
611
|
-
scopeAccesses=[
|
|
612
|
-
{
|
|
613
|
-
"entityId": "group_id",
|
|
614
|
-
"type": "WRITE",
|
|
615
|
-
"entityType": "GROUP",
|
|
616
|
-
}
|
|
617
|
-
],
|
|
618
|
-
applyToSubScopes=True,
|
|
619
|
-
)
|
|
620
|
-
```
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
Example of deleting the access from a folder and its subfolders using the path.
|
|
624
|
-
|
|
625
|
-
```python
|
|
626
|
-
unique_sdk.Folder.remove_access(
|
|
627
|
-
user_id=user_id,
|
|
628
|
-
company_id=company_id,
|
|
629
|
-
folderPath="/Company/folder1/folder2"
|
|
630
|
-
scopeAccesses=[
|
|
631
|
-
{
|
|
632
|
-
"entityId": "group_id",
|
|
633
|
-
"type": "WRITE",
|
|
634
|
-
"entityType": "GROUP",
|
|
635
|
-
}
|
|
636
|
-
],
|
|
637
|
-
applyToSubScopes=True,
|
|
638
|
-
)
|
|
639
|
-
```
|
|
640
|
-
|
|
641
476
|
### Message
|
|
642
477
|
|
|
643
478
|
#### `unique_sdk.Message.list`
|
|
@@ -946,6 +781,175 @@ assessment = unique_sdk.MessageAssessment.modify(
|
|
|
946
781
|
)
|
|
947
782
|
```
|
|
948
783
|
|
|
784
|
+
### Folder
|
|
785
|
+
|
|
786
|
+
#### `unique_sdk.Folder.get`
|
|
787
|
+
|
|
788
|
+
Get a folder by scope id or by path.
|
|
789
|
+
|
|
790
|
+
By scope id:
|
|
791
|
+
|
|
792
|
+
```python
|
|
793
|
+
unique_sdk.Folder.get_info(
|
|
794
|
+
user_id=user_id,
|
|
795
|
+
company_id=company_id,
|
|
796
|
+
scopeId="scope_w78wfn114va9o22s13r03yq",
|
|
797
|
+
)
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
By path:
|
|
801
|
+
|
|
802
|
+
```python
|
|
803
|
+
unique_sdk.Folder.get_info(
|
|
804
|
+
user_id=user_id,
|
|
805
|
+
company_id=company_id,
|
|
806
|
+
folderPath="/Company/Atlas/Due Dilligence/Arch,
|
|
807
|
+
)
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
#### `unique_sdk.Folder.create_paths`
|
|
811
|
+
|
|
812
|
+
Create each folder in the provided list of paths if it does not already exist.
|
|
813
|
+
|
|
814
|
+
```python
|
|
815
|
+
unique_sdk.Folder.create_paths(
|
|
816
|
+
user_id=user_id,
|
|
817
|
+
company_id=company_id,
|
|
818
|
+
paths=["/unique/path1", "/unique/path2"],
|
|
819
|
+
)
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
#### `unique_sdk.Folder.update_ingestion_config`
|
|
823
|
+
|
|
824
|
+
Allows you to update the ingestion config of a folder and choose whether to apply to the subscopes or not: `
|
|
825
|
+
|
|
826
|
+
- `ingestionConfig`
|
|
827
|
+
- `applyToSubScopes`
|
|
828
|
+
|
|
829
|
+
The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
|
|
830
|
+
|
|
831
|
+
Example of updating the ingestion config of a folder and its subfolders using the id.
|
|
832
|
+
|
|
833
|
+
```python
|
|
834
|
+
unique_sdk.Folder.update_ingestion_config(
|
|
835
|
+
user_id=user_id,
|
|
836
|
+
company_id=company_id,
|
|
837
|
+
scopeId="scope_qbnkde820dbmuw2900,
|
|
838
|
+
ingestionConfig={
|
|
839
|
+
"chunkStrategy": "default",
|
|
840
|
+
"uniqueIngestionMode": "standard",
|
|
841
|
+
},
|
|
842
|
+
applyToSubScopes=True
|
|
843
|
+
)
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
Example of updating the ingestion config of a folder and its subfolders using the path.
|
|
847
|
+
|
|
848
|
+
```python
|
|
849
|
+
unique_sdk.Folder.update_ingestion_config(
|
|
850
|
+
user_id=user_id,
|
|
851
|
+
company_id=company_id,
|
|
852
|
+
folderPath="/Company/folder1/folder2",
|
|
853
|
+
ingestionConfig={
|
|
854
|
+
"chunkStrategy": "default",
|
|
855
|
+
"uniqueIngestionMode": "standard",
|
|
856
|
+
},
|
|
857
|
+
applyToSubScopes=True
|
|
858
|
+
)
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
#### `unique_sdk.Folder.add_access`
|
|
862
|
+
|
|
863
|
+
Allows you to add access to a folder and apply to the subfolders or not: `
|
|
864
|
+
|
|
865
|
+
- `scopeAccesses`
|
|
866
|
+
- `applyToSubScopes`
|
|
867
|
+
|
|
868
|
+
The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
|
|
869
|
+
|
|
870
|
+
Example of adding access to a folder and its subfolders using the id.
|
|
871
|
+
|
|
872
|
+
```python
|
|
873
|
+
unique_sdk.Folder.add_access(
|
|
874
|
+
user_id=user_id,
|
|
875
|
+
company_id=company_id,
|
|
876
|
+
scopeId="scope_231e4kjn4foffww34",
|
|
877
|
+
scopeAccesses=[
|
|
878
|
+
{
|
|
879
|
+
"entityId": "group_id",
|
|
880
|
+
"type": "WRITE",
|
|
881
|
+
"entityType": "GROUP",
|
|
882
|
+
}
|
|
883
|
+
],
|
|
884
|
+
applyToSubScopes=True,
|
|
885
|
+
)
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
Example of adding access to a folder and its subfolders using the folder path.
|
|
889
|
+
|
|
890
|
+
```python
|
|
891
|
+
unique_sdk.Folder.add_access(
|
|
892
|
+
user_id=user_id,
|
|
893
|
+
company_id=company_id,
|
|
894
|
+
folderPath="/Company/folder1/folder2"
|
|
895
|
+
scopeAccesses=[
|
|
896
|
+
{
|
|
897
|
+
"entityId": "group_id",
|
|
898
|
+
"type": "WRITE",
|
|
899
|
+
"entityType": "GROUP",
|
|
900
|
+
}
|
|
901
|
+
],
|
|
902
|
+
applyToSubScopes=True,
|
|
903
|
+
)
|
|
904
|
+
```
|
|
905
|
+
|
|
906
|
+
#### `unique_sdk.Folder.remove_access`
|
|
907
|
+
|
|
908
|
+
Allows you to delete access from a folder and apply to the subfolders or not: `
|
|
909
|
+
|
|
910
|
+
- `scopeAccesses`
|
|
911
|
+
- `applyToSubScopes`
|
|
912
|
+
|
|
913
|
+
The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
Example of deleting the access from a folder and its subfolders using the id.
|
|
917
|
+
|
|
918
|
+
```python
|
|
919
|
+
unique_sdk.Folder.remove_access(
|
|
920
|
+
user_id=user_id,
|
|
921
|
+
company_id=company_id,
|
|
922
|
+
scopeId="scope_dwekjnf3330woioppm,
|
|
923
|
+
scopeAccesses=[
|
|
924
|
+
{
|
|
925
|
+
"entityId": "group_id",
|
|
926
|
+
"type": "WRITE",
|
|
927
|
+
"entityType": "GROUP",
|
|
928
|
+
}
|
|
929
|
+
],
|
|
930
|
+
applyToSubScopes=True,
|
|
931
|
+
)
|
|
932
|
+
```
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
Example of deleting the access from a folder and its subfolders using the path.
|
|
936
|
+
|
|
937
|
+
```python
|
|
938
|
+
unique_sdk.Folder.remove_access(
|
|
939
|
+
user_id=user_id,
|
|
940
|
+
company_id=company_id,
|
|
941
|
+
folderPath="/Company/folder1/folder2"
|
|
942
|
+
scopeAccesses=[
|
|
943
|
+
{
|
|
944
|
+
"entityId": "group_id",
|
|
945
|
+
"type": "WRITE",
|
|
946
|
+
"entityType": "GROUP",
|
|
947
|
+
}
|
|
948
|
+
],
|
|
949
|
+
applyToSubScopes=True,
|
|
950
|
+
)
|
|
951
|
+
```
|
|
952
|
+
|
|
949
953
|
## UniqueQL
|
|
950
954
|
|
|
951
955
|
[UniqueQL](https://unique-ch.atlassian.net/wiki/x/coAXHQ) is an advanced query language designed to enhance search capabilities within various search modes such as Vector, Full-Text Search (FTS), and Combined. This query language enables users to perform detailed searches by filtering through metadata attributes like filenames, URLs, dates, and more. UniqueQL is versatile and can be translated into different query formats for various database systems, including PostgreSQL and Qdrant.
|
|
@@ -1051,7 +1055,7 @@ pdfFile = download_content(
|
|
|
1051
1055
|
content_id="cont_12412",
|
|
1052
1056
|
filename="hello.pdf",
|
|
1053
1057
|
chat_id=None # If specified, it downloads it from the chat
|
|
1054
|
-
|
|
1058
|
+
)
|
|
1055
1059
|
```
|
|
1056
1060
|
|
|
1057
1061
|
#### `unique_sdk.utils.file_io.upload_file`
|
|
@@ -1214,6 +1218,47 @@ hello = "hello you!"
|
|
|
1214
1218
|
searchContext = unique_sdk.utils.token.count_tokens(hello)
|
|
1215
1219
|
```
|
|
1216
1220
|
|
|
1221
|
+
### Chat In Space
|
|
1222
|
+
|
|
1223
|
+
#### `unique_sdk.utils.chat_in_space.send_message_and_wait_for_completion`
|
|
1224
|
+
|
|
1225
|
+
The following script enables you to chat within a space using an assistant. You must provide an `assistantId` (e.g., `assistant_hjcdga64bkcjnhu4`) and the message `text` to initiate the conversation. You can send the message in an existing chat by specifying a `chat_id`, or omit the `chat_id` to automatically create a new chat session. Check the optional parameteres list for more configs.
|
|
1226
|
+
|
|
1227
|
+
The script sends a prompt asynchronously and continuously polls for completion, which is determined when the `stoppedStreamingAt` field of the message becomes non-null.
|
|
1228
|
+
|
|
1229
|
+
**Optional parameters:**
|
|
1230
|
+
- `tool_choices`: A list of tool names to be used for the message (e.g., `["WebSearch"]`). If not provided, no tools will be used.
|
|
1231
|
+
- `scope_rules`: A dictionary specifying scope rules for the message, allowing you to restrict the context or data sources available to the assistant.
|
|
1232
|
+
- `chat_id`: The ID of the chat where the message should be sent. If omitted, a new chat will be created.
|
|
1233
|
+
- `poll_interval`: The number of seconds to wait between polling attempts (default: `1` second).
|
|
1234
|
+
- `max_wait`: The maximum number of seconds to wait for the message to complete (default: `60` seconds).
|
|
1235
|
+
|
|
1236
|
+
The script ensures you can flexibly interact with spaces in new or ongoing chats, with fine-grained control over tools, context, and polling behavior.
|
|
1237
|
+
|
|
1238
|
+
```python
|
|
1239
|
+
latest_message = unique_sdk.utils.send_message_and_wait_for_completion(
|
|
1240
|
+
user_id=user_id,
|
|
1241
|
+
company_id=company_id,
|
|
1242
|
+
assistant_id=assistant_id,
|
|
1243
|
+
text="Tell me a short story.",
|
|
1244
|
+
chat_id=chat_id, # Optional - if no chat id is specified, a new chat will be created
|
|
1245
|
+
tool_choices=["WebSearch"],
|
|
1246
|
+
scope_rules={
|
|
1247
|
+
"or": [
|
|
1248
|
+
{
|
|
1249
|
+
"operator": "in",
|
|
1250
|
+
"path": [
|
|
1251
|
+
"contentId"
|
|
1252
|
+
],
|
|
1253
|
+
"value": [
|
|
1254
|
+
"cont_u888z7cazxxm4lugfdjq7pks"
|
|
1255
|
+
]
|
|
1256
|
+
}
|
|
1257
|
+
]
|
|
1258
|
+
},
|
|
1259
|
+
)
|
|
1260
|
+
```
|
|
1261
|
+
|
|
1217
1262
|
## Error Handling
|
|
1218
1263
|
|
|
1219
1264
|
## Examples
|
|
@@ -1231,6 +1276,9 @@ All notable changes to this project will be documented in this file.
|
|
|
1231
1276
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
1232
1277
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
1233
1278
|
|
|
1279
|
+
## [0.9.39] - 2025-07-18
|
|
1280
|
+
- Add script to chat in a space.
|
|
1281
|
+
|
|
1234
1282
|
## [0.9.38] - 2025-07-18
|
|
1235
1283
|
- [Experimental] Add support for Unique OpenAI proxy. You can now use the OpenAI SDK directly through Unique. Checkout how to do this and a few examples here: `tutorials/unique_basics/sdk_examples/openai_scripts.py`.
|
|
1236
1284
|
|
|
@@ -12,7 +12,6 @@ The Unique Python SDK provides access to the public API of Unique FinanceGPT. It
|
|
|
12
12
|
4. [Webhook Triggers](#webhook-triggers)
|
|
13
13
|
5. [Available API Resources](#available-api-resources)
|
|
14
14
|
- [Content](#content)
|
|
15
|
-
- [Folder](#folder)
|
|
16
15
|
- [Message](#message)
|
|
17
16
|
- [Chat Completion](#chat-completion)
|
|
18
17
|
- [Embeddings](#embeddings)
|
|
@@ -30,6 +29,7 @@ The Unique Python SDK provides access to the public API of Unique FinanceGPT. It
|
|
|
30
29
|
- [File Io](#file-io)
|
|
31
30
|
- [Sources](#sources)
|
|
32
31
|
- [token](#token)
|
|
32
|
+
- [Chat In Space](#chat-in-space)
|
|
33
33
|
8. [Error Handling](#error-handling)
|
|
34
34
|
9. [Examples](#examples)
|
|
35
35
|
|
|
@@ -228,8 +228,12 @@ unique_sdk.Message.modify(
|
|
|
228
228
|
- [Content](#content)
|
|
229
229
|
- [Message](#message)
|
|
230
230
|
- [Chat Completion](#chat-completion)
|
|
231
|
+
- [Embeddings](#embeddings)
|
|
232
|
+
- [Acronyms](#acronyms)
|
|
231
233
|
- [Search](#search)
|
|
232
234
|
- [Search String](#search-string)
|
|
235
|
+
- [Short Term Memory](#short-term-memory)
|
|
236
|
+
- [Message Assessment](#message-assessment)
|
|
233
237
|
- [Folder](#folder)
|
|
234
238
|
|
|
235
239
|
Most of the API services provide an asynchronous version of the method. The async methods are suffixed with `_async`.
|
|
@@ -453,175 +457,6 @@ Allows you to ingest a magic table sheet, each row is processed and converted in
|
|
|
453
457
|
unique_sdk.Content.ingest_magic_table_sheets(**params)
|
|
454
458
|
```
|
|
455
459
|
|
|
456
|
-
### Folder
|
|
457
|
-
|
|
458
|
-
#### `unique_sdk.Folder.get`
|
|
459
|
-
|
|
460
|
-
Get a folder by scope id or by path.
|
|
461
|
-
|
|
462
|
-
By scope id:
|
|
463
|
-
|
|
464
|
-
```python
|
|
465
|
-
unique_sdk.Folder.get_info(
|
|
466
|
-
user_id=user_id,
|
|
467
|
-
company_id=company_id,
|
|
468
|
-
scopeId="scope_w78wfn114va9o22s13r03yq",
|
|
469
|
-
)
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
By path:
|
|
473
|
-
|
|
474
|
-
```python
|
|
475
|
-
unique_sdk.Folder.get_info(
|
|
476
|
-
user_id=user_id,
|
|
477
|
-
company_id=company_id,
|
|
478
|
-
folderPath="/Company/Atlas/Due Dilligence/Arch,
|
|
479
|
-
)
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
#### `unique_sdk.Folder.create_paths`
|
|
483
|
-
|
|
484
|
-
Create each folder in the provided list of paths if it does not already exist.
|
|
485
|
-
|
|
486
|
-
```python
|
|
487
|
-
unique_sdk.Folder.create_paths(
|
|
488
|
-
user_id=user_id,
|
|
489
|
-
company_id=company_id,
|
|
490
|
-
paths=["/unique/path1", "/unique/path2"],
|
|
491
|
-
)
|
|
492
|
-
```
|
|
493
|
-
|
|
494
|
-
#### `unique_sdk.Folder.update_ingestion_config`
|
|
495
|
-
|
|
496
|
-
Allows you to update the ingestion config of a folder and choose whether to apply to the subscopes or not: `
|
|
497
|
-
|
|
498
|
-
- `ingestionConfig`
|
|
499
|
-
- `applyToSubScopes`
|
|
500
|
-
|
|
501
|
-
The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
|
|
502
|
-
|
|
503
|
-
Example of updating the ingestion config of a folder and its subfolders using the id.
|
|
504
|
-
|
|
505
|
-
```python
|
|
506
|
-
unique_sdk.Folder.update_ingestion_config(
|
|
507
|
-
user_id=user_id,
|
|
508
|
-
company_id=company_id,
|
|
509
|
-
scopeId="scope_qbnkde820dbmuw2900,
|
|
510
|
-
ingestionConfig={
|
|
511
|
-
"chunkStrategy": "default",
|
|
512
|
-
"uniqueIngestionMode": "standard",
|
|
513
|
-
},
|
|
514
|
-
applyToSubScopes=True
|
|
515
|
-
)
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
Example of updating the ingestion config of a folder and its subfolders using the path.
|
|
519
|
-
|
|
520
|
-
```python
|
|
521
|
-
unique_sdk.Folder.update_ingestion_config(
|
|
522
|
-
user_id=user_id,
|
|
523
|
-
company_id=company_id,
|
|
524
|
-
folderPath="/Company/folder1/folder2",
|
|
525
|
-
ingestionConfig={
|
|
526
|
-
"chunkStrategy": "default",
|
|
527
|
-
"uniqueIngestionMode": "standard",
|
|
528
|
-
},
|
|
529
|
-
applyToSubScopes=True
|
|
530
|
-
)
|
|
531
|
-
```
|
|
532
|
-
|
|
533
|
-
#### `unique_sdk.Folder.add_access`
|
|
534
|
-
|
|
535
|
-
Allows you to add access to a folder and apply to the subfolders or not: `
|
|
536
|
-
|
|
537
|
-
- `scopeAccesses`
|
|
538
|
-
- `applyToSubScopes`
|
|
539
|
-
|
|
540
|
-
The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
|
|
541
|
-
|
|
542
|
-
Example of adding access to a folder and its subfolders using the id.
|
|
543
|
-
|
|
544
|
-
```python
|
|
545
|
-
unique_sdk.Folder.add_access(
|
|
546
|
-
user_id=user_id,
|
|
547
|
-
company_id=company_id,
|
|
548
|
-
scopeId="scope_231e4kjn4foffww34",
|
|
549
|
-
scopeAccesses=[
|
|
550
|
-
{
|
|
551
|
-
"entityId": "group_id",
|
|
552
|
-
"type": "WRITE",
|
|
553
|
-
"entityType": "GROUP",
|
|
554
|
-
}
|
|
555
|
-
],
|
|
556
|
-
applyToSubScopes=True,
|
|
557
|
-
)
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
Example of adding access to a folder and its subfolders using the folder path.
|
|
561
|
-
|
|
562
|
-
```python
|
|
563
|
-
unique_sdk.Folder.add_access(
|
|
564
|
-
user_id=user_id,
|
|
565
|
-
company_id=company_id,
|
|
566
|
-
folderPath="/Company/folder1/folder2"
|
|
567
|
-
scopeAccesses=[
|
|
568
|
-
{
|
|
569
|
-
"entityId": "group_id",
|
|
570
|
-
"type": "WRITE",
|
|
571
|
-
"entityType": "GROUP",
|
|
572
|
-
}
|
|
573
|
-
],
|
|
574
|
-
applyToSubScopes=True,
|
|
575
|
-
)
|
|
576
|
-
```
|
|
577
|
-
|
|
578
|
-
#### `unique_sdk.Folder.remove_access`
|
|
579
|
-
|
|
580
|
-
Allows you to delete access from a folder and apply to the subfolders or not: `
|
|
581
|
-
|
|
582
|
-
- `scopeAccesses`
|
|
583
|
-
- `applyToSubScopes`
|
|
584
|
-
|
|
585
|
-
The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
Example of deleting the access from a folder and its subfolders using the id.
|
|
589
|
-
|
|
590
|
-
```python
|
|
591
|
-
unique_sdk.Folder.remove_access(
|
|
592
|
-
user_id=user_id,
|
|
593
|
-
company_id=company_id,
|
|
594
|
-
scopeId="scope_dwekjnf3330woioppm,
|
|
595
|
-
scopeAccesses=[
|
|
596
|
-
{
|
|
597
|
-
"entityId": "group_id",
|
|
598
|
-
"type": "WRITE",
|
|
599
|
-
"entityType": "GROUP",
|
|
600
|
-
}
|
|
601
|
-
],
|
|
602
|
-
applyToSubScopes=True,
|
|
603
|
-
)
|
|
604
|
-
```
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
Example of deleting the access from a folder and its subfolders using the path.
|
|
608
|
-
|
|
609
|
-
```python
|
|
610
|
-
unique_sdk.Folder.remove_access(
|
|
611
|
-
user_id=user_id,
|
|
612
|
-
company_id=company_id,
|
|
613
|
-
folderPath="/Company/folder1/folder2"
|
|
614
|
-
scopeAccesses=[
|
|
615
|
-
{
|
|
616
|
-
"entityId": "group_id",
|
|
617
|
-
"type": "WRITE",
|
|
618
|
-
"entityType": "GROUP",
|
|
619
|
-
}
|
|
620
|
-
],
|
|
621
|
-
applyToSubScopes=True,
|
|
622
|
-
)
|
|
623
|
-
```
|
|
624
|
-
|
|
625
460
|
### Message
|
|
626
461
|
|
|
627
462
|
#### `unique_sdk.Message.list`
|
|
@@ -930,6 +765,175 @@ assessment = unique_sdk.MessageAssessment.modify(
|
|
|
930
765
|
)
|
|
931
766
|
```
|
|
932
767
|
|
|
768
|
+
### Folder
|
|
769
|
+
|
|
770
|
+
#### `unique_sdk.Folder.get`
|
|
771
|
+
|
|
772
|
+
Get a folder by scope id or by path.
|
|
773
|
+
|
|
774
|
+
By scope id:
|
|
775
|
+
|
|
776
|
+
```python
|
|
777
|
+
unique_sdk.Folder.get_info(
|
|
778
|
+
user_id=user_id,
|
|
779
|
+
company_id=company_id,
|
|
780
|
+
scopeId="scope_w78wfn114va9o22s13r03yq",
|
|
781
|
+
)
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
By path:
|
|
785
|
+
|
|
786
|
+
```python
|
|
787
|
+
unique_sdk.Folder.get_info(
|
|
788
|
+
user_id=user_id,
|
|
789
|
+
company_id=company_id,
|
|
790
|
+
folderPath="/Company/Atlas/Due Dilligence/Arch,
|
|
791
|
+
)
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
#### `unique_sdk.Folder.create_paths`
|
|
795
|
+
|
|
796
|
+
Create each folder in the provided list of paths if it does not already exist.
|
|
797
|
+
|
|
798
|
+
```python
|
|
799
|
+
unique_sdk.Folder.create_paths(
|
|
800
|
+
user_id=user_id,
|
|
801
|
+
company_id=company_id,
|
|
802
|
+
paths=["/unique/path1", "/unique/path2"],
|
|
803
|
+
)
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
#### `unique_sdk.Folder.update_ingestion_config`
|
|
807
|
+
|
|
808
|
+
Allows you to update the ingestion config of a folder and choose whether to apply to the subscopes or not: `
|
|
809
|
+
|
|
810
|
+
- `ingestionConfig`
|
|
811
|
+
- `applyToSubScopes`
|
|
812
|
+
|
|
813
|
+
The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
|
|
814
|
+
|
|
815
|
+
Example of updating the ingestion config of a folder and its subfolders using the id.
|
|
816
|
+
|
|
817
|
+
```python
|
|
818
|
+
unique_sdk.Folder.update_ingestion_config(
|
|
819
|
+
user_id=user_id,
|
|
820
|
+
company_id=company_id,
|
|
821
|
+
scopeId="scope_qbnkde820dbmuw2900,
|
|
822
|
+
ingestionConfig={
|
|
823
|
+
"chunkStrategy": "default",
|
|
824
|
+
"uniqueIngestionMode": "standard",
|
|
825
|
+
},
|
|
826
|
+
applyToSubScopes=True
|
|
827
|
+
)
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
Example of updating the ingestion config of a folder and its subfolders using the path.
|
|
831
|
+
|
|
832
|
+
```python
|
|
833
|
+
unique_sdk.Folder.update_ingestion_config(
|
|
834
|
+
user_id=user_id,
|
|
835
|
+
company_id=company_id,
|
|
836
|
+
folderPath="/Company/folder1/folder2",
|
|
837
|
+
ingestionConfig={
|
|
838
|
+
"chunkStrategy": "default",
|
|
839
|
+
"uniqueIngestionMode": "standard",
|
|
840
|
+
},
|
|
841
|
+
applyToSubScopes=True
|
|
842
|
+
)
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
#### `unique_sdk.Folder.add_access`
|
|
846
|
+
|
|
847
|
+
Allows you to add access to a folder and apply to the subfolders or not: `
|
|
848
|
+
|
|
849
|
+
- `scopeAccesses`
|
|
850
|
+
- `applyToSubScopes`
|
|
851
|
+
|
|
852
|
+
The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
|
|
853
|
+
|
|
854
|
+
Example of adding access to a folder and its subfolders using the id.
|
|
855
|
+
|
|
856
|
+
```python
|
|
857
|
+
unique_sdk.Folder.add_access(
|
|
858
|
+
user_id=user_id,
|
|
859
|
+
company_id=company_id,
|
|
860
|
+
scopeId="scope_231e4kjn4foffww34",
|
|
861
|
+
scopeAccesses=[
|
|
862
|
+
{
|
|
863
|
+
"entityId": "group_id",
|
|
864
|
+
"type": "WRITE",
|
|
865
|
+
"entityType": "GROUP",
|
|
866
|
+
}
|
|
867
|
+
],
|
|
868
|
+
applyToSubScopes=True,
|
|
869
|
+
)
|
|
870
|
+
```
|
|
871
|
+
|
|
872
|
+
Example of adding access to a folder and its subfolders using the folder path.
|
|
873
|
+
|
|
874
|
+
```python
|
|
875
|
+
unique_sdk.Folder.add_access(
|
|
876
|
+
user_id=user_id,
|
|
877
|
+
company_id=company_id,
|
|
878
|
+
folderPath="/Company/folder1/folder2"
|
|
879
|
+
scopeAccesses=[
|
|
880
|
+
{
|
|
881
|
+
"entityId": "group_id",
|
|
882
|
+
"type": "WRITE",
|
|
883
|
+
"entityType": "GROUP",
|
|
884
|
+
}
|
|
885
|
+
],
|
|
886
|
+
applyToSubScopes=True,
|
|
887
|
+
)
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
#### `unique_sdk.Folder.remove_access`
|
|
891
|
+
|
|
892
|
+
Allows you to delete access from a folder and apply to the subfolders or not: `
|
|
893
|
+
|
|
894
|
+
- `scopeAccesses`
|
|
895
|
+
- `applyToSubScopes`
|
|
896
|
+
|
|
897
|
+
The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
Example of deleting the access from a folder and its subfolders using the id.
|
|
901
|
+
|
|
902
|
+
```python
|
|
903
|
+
unique_sdk.Folder.remove_access(
|
|
904
|
+
user_id=user_id,
|
|
905
|
+
company_id=company_id,
|
|
906
|
+
scopeId="scope_dwekjnf3330woioppm,
|
|
907
|
+
scopeAccesses=[
|
|
908
|
+
{
|
|
909
|
+
"entityId": "group_id",
|
|
910
|
+
"type": "WRITE",
|
|
911
|
+
"entityType": "GROUP",
|
|
912
|
+
}
|
|
913
|
+
],
|
|
914
|
+
applyToSubScopes=True,
|
|
915
|
+
)
|
|
916
|
+
```
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
Example of deleting the access from a folder and its subfolders using the path.
|
|
920
|
+
|
|
921
|
+
```python
|
|
922
|
+
unique_sdk.Folder.remove_access(
|
|
923
|
+
user_id=user_id,
|
|
924
|
+
company_id=company_id,
|
|
925
|
+
folderPath="/Company/folder1/folder2"
|
|
926
|
+
scopeAccesses=[
|
|
927
|
+
{
|
|
928
|
+
"entityId": "group_id",
|
|
929
|
+
"type": "WRITE",
|
|
930
|
+
"entityType": "GROUP",
|
|
931
|
+
}
|
|
932
|
+
],
|
|
933
|
+
applyToSubScopes=True,
|
|
934
|
+
)
|
|
935
|
+
```
|
|
936
|
+
|
|
933
937
|
## UniqueQL
|
|
934
938
|
|
|
935
939
|
[UniqueQL](https://unique-ch.atlassian.net/wiki/x/coAXHQ) is an advanced query language designed to enhance search capabilities within various search modes such as Vector, Full-Text Search (FTS), and Combined. This query language enables users to perform detailed searches by filtering through metadata attributes like filenames, URLs, dates, and more. UniqueQL is versatile and can be translated into different query formats for various database systems, including PostgreSQL and Qdrant.
|
|
@@ -1035,7 +1039,7 @@ pdfFile = download_content(
|
|
|
1035
1039
|
content_id="cont_12412",
|
|
1036
1040
|
filename="hello.pdf",
|
|
1037
1041
|
chat_id=None # If specified, it downloads it from the chat
|
|
1038
|
-
|
|
1042
|
+
)
|
|
1039
1043
|
```
|
|
1040
1044
|
|
|
1041
1045
|
#### `unique_sdk.utils.file_io.upload_file`
|
|
@@ -1198,6 +1202,47 @@ hello = "hello you!"
|
|
|
1198
1202
|
searchContext = unique_sdk.utils.token.count_tokens(hello)
|
|
1199
1203
|
```
|
|
1200
1204
|
|
|
1205
|
+
### Chat In Space
|
|
1206
|
+
|
|
1207
|
+
#### `unique_sdk.utils.chat_in_space.send_message_and_wait_for_completion`
|
|
1208
|
+
|
|
1209
|
+
The following script enables you to chat within a space using an assistant. You must provide an `assistantId` (e.g., `assistant_hjcdga64bkcjnhu4`) and the message `text` to initiate the conversation. You can send the message in an existing chat by specifying a `chat_id`, or omit the `chat_id` to automatically create a new chat session. Check the optional parameteres list for more configs.
|
|
1210
|
+
|
|
1211
|
+
The script sends a prompt asynchronously and continuously polls for completion, which is determined when the `stoppedStreamingAt` field of the message becomes non-null.
|
|
1212
|
+
|
|
1213
|
+
**Optional parameters:**
|
|
1214
|
+
- `tool_choices`: A list of tool names to be used for the message (e.g., `["WebSearch"]`). If not provided, no tools will be used.
|
|
1215
|
+
- `scope_rules`: A dictionary specifying scope rules for the message, allowing you to restrict the context or data sources available to the assistant.
|
|
1216
|
+
- `chat_id`: The ID of the chat where the message should be sent. If omitted, a new chat will be created.
|
|
1217
|
+
- `poll_interval`: The number of seconds to wait between polling attempts (default: `1` second).
|
|
1218
|
+
- `max_wait`: The maximum number of seconds to wait for the message to complete (default: `60` seconds).
|
|
1219
|
+
|
|
1220
|
+
The script ensures you can flexibly interact with spaces in new or ongoing chats, with fine-grained control over tools, context, and polling behavior.
|
|
1221
|
+
|
|
1222
|
+
```python
|
|
1223
|
+
latest_message = unique_sdk.utils.send_message_and_wait_for_completion(
|
|
1224
|
+
user_id=user_id,
|
|
1225
|
+
company_id=company_id,
|
|
1226
|
+
assistant_id=assistant_id,
|
|
1227
|
+
text="Tell me a short story.",
|
|
1228
|
+
chat_id=chat_id, # Optional - if no chat id is specified, a new chat will be created
|
|
1229
|
+
tool_choices=["WebSearch"],
|
|
1230
|
+
scope_rules={
|
|
1231
|
+
"or": [
|
|
1232
|
+
{
|
|
1233
|
+
"operator": "in",
|
|
1234
|
+
"path": [
|
|
1235
|
+
"contentId"
|
|
1236
|
+
],
|
|
1237
|
+
"value": [
|
|
1238
|
+
"cont_u888z7cazxxm4lugfdjq7pks"
|
|
1239
|
+
]
|
|
1240
|
+
}
|
|
1241
|
+
]
|
|
1242
|
+
},
|
|
1243
|
+
)
|
|
1244
|
+
```
|
|
1245
|
+
|
|
1201
1246
|
## Error Handling
|
|
1202
1247
|
|
|
1203
1248
|
## Examples
|
|
@@ -86,6 +86,7 @@ from unique_sdk.api_resources._acronyms import Acronyms as Acronyms
|
|
|
86
86
|
from unique_sdk.api_resources._message_assessment import (
|
|
87
87
|
MessageAssessment as MessageAssessment,
|
|
88
88
|
)
|
|
89
|
+
from unique_sdk.api_resources._space import Space as Space
|
|
89
90
|
|
|
90
91
|
# Unique QL
|
|
91
92
|
from unique_sdk._unique_ql import UQLOperator as UQLOperator
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Unpack, cast
|
|
2
|
+
|
|
3
|
+
from unique_sdk._api_resource import APIResource
|
|
4
|
+
from unique_sdk._request_options import RequestOptions
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Space(APIResource["Space"]):
|
|
8
|
+
OBJECT_NAME: ClassVar[Literal["space"]] = "space"
|
|
9
|
+
|
|
10
|
+
class CreateMessageParams(RequestOptions):
|
|
11
|
+
"""
|
|
12
|
+
Parameters for querying the assistant for a message.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
chatId: str | None = None
|
|
16
|
+
assistantId: str
|
|
17
|
+
text: str | None = None
|
|
18
|
+
toolChoices: List[str] = None
|
|
19
|
+
scopeRules: dict | None = None
|
|
20
|
+
|
|
21
|
+
class Reference(TypedDict):
|
|
22
|
+
"""
|
|
23
|
+
Reference information for a message.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
name: str
|
|
27
|
+
url: str | None
|
|
28
|
+
sequenceNumber: int
|
|
29
|
+
originalIndex: List[int] | None
|
|
30
|
+
sourceId: str
|
|
31
|
+
source: str
|
|
32
|
+
|
|
33
|
+
class Assessment(TypedDict):
|
|
34
|
+
"""
|
|
35
|
+
Assessment information for a message.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
id: str
|
|
39
|
+
createdAt: str
|
|
40
|
+
updatedAt: str
|
|
41
|
+
messageId: str
|
|
42
|
+
status: str
|
|
43
|
+
explanation: str | None
|
|
44
|
+
label: str | None
|
|
45
|
+
type: str | None
|
|
46
|
+
title: str | None
|
|
47
|
+
companyId: str
|
|
48
|
+
userId: str
|
|
49
|
+
isVisible: bool
|
|
50
|
+
createdBy: str | None
|
|
51
|
+
|
|
52
|
+
class Message(TypedDict):
|
|
53
|
+
"""
|
|
54
|
+
Represents a message in the space.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
id: str
|
|
58
|
+
chatId: str
|
|
59
|
+
text: str | None = None
|
|
60
|
+
originalText: str | None = None
|
|
61
|
+
role: Literal["system", "user", "assistant"]
|
|
62
|
+
debugInfo: Optional[Dict[str, Any]] = None
|
|
63
|
+
completedAt: str | None
|
|
64
|
+
createdAt: str | None
|
|
65
|
+
updatedAt: str | None
|
|
66
|
+
stoppedStreamingAt: str | None
|
|
67
|
+
assessment: Optional[List["Space.Reference"]]
|
|
68
|
+
messageAssessment: Optional[List["Space.Assessment"]]
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def create_message(
|
|
72
|
+
cls,
|
|
73
|
+
user_id: str,
|
|
74
|
+
company_id: str,
|
|
75
|
+
**params: Unpack["Space.CreateMessageParams"],
|
|
76
|
+
) -> "Space.Message":
|
|
77
|
+
"""
|
|
78
|
+
Send a message in a space.
|
|
79
|
+
"""
|
|
80
|
+
return cast(
|
|
81
|
+
"Space.Message",
|
|
82
|
+
cls._static_request(
|
|
83
|
+
"post",
|
|
84
|
+
"/space/message",
|
|
85
|
+
user_id,
|
|
86
|
+
company_id,
|
|
87
|
+
params=params,
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
@classmethod
|
|
92
|
+
async def create_message_async(
|
|
93
|
+
cls,
|
|
94
|
+
user_id: str,
|
|
95
|
+
company_id: str,
|
|
96
|
+
**params: Unpack["Space.CreateMessageParams"],
|
|
97
|
+
) -> "Space.Message":
|
|
98
|
+
"""
|
|
99
|
+
Async send a message in a space.
|
|
100
|
+
"""
|
|
101
|
+
return cast(
|
|
102
|
+
"Space.Message",
|
|
103
|
+
await cls._static_request_async(
|
|
104
|
+
"post",
|
|
105
|
+
"/space/message",
|
|
106
|
+
user_id,
|
|
107
|
+
company_id,
|
|
108
|
+
params=params,
|
|
109
|
+
),
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
@classmethod
|
|
113
|
+
def get_latest_message(
|
|
114
|
+
cls, user_id: str, company_id: str, chat_id: str
|
|
115
|
+
) -> "Space.Message":
|
|
116
|
+
"""
|
|
117
|
+
Get the latest message in a space.
|
|
118
|
+
"""
|
|
119
|
+
return cast(
|
|
120
|
+
"Space.Message",
|
|
121
|
+
cls._static_request(
|
|
122
|
+
"get",
|
|
123
|
+
f"/space/{chat_id}/messages/latest",
|
|
124
|
+
user_id,
|
|
125
|
+
company_id,
|
|
126
|
+
),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
@classmethod
|
|
130
|
+
async def get_latest_message_async(
|
|
131
|
+
cls, user_id: str, company_id: str, chat_id: str
|
|
132
|
+
) -> "Space.Message":
|
|
133
|
+
"""
|
|
134
|
+
Async get the latest message in a space.
|
|
135
|
+
"""
|
|
136
|
+
return cast(
|
|
137
|
+
"Space.Message",
|
|
138
|
+
await cls._static_request_async(
|
|
139
|
+
"get",
|
|
140
|
+
f"/space/{chat_id}/messages/latest",
|
|
141
|
+
user_id,
|
|
142
|
+
company_id,
|
|
143
|
+
),
|
|
144
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
from unique_sdk.api_resources._space import Space
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def send_message_and_wait_for_completion(
|
|
8
|
+
user_id: str,
|
|
9
|
+
company_id: str,
|
|
10
|
+
assistant_id: str,
|
|
11
|
+
text: str,
|
|
12
|
+
tool_choices: List[str] = None,
|
|
13
|
+
scope_rules: dict | None = None,
|
|
14
|
+
chat_id: str = None,
|
|
15
|
+
poll_interval: float = 1.0,
|
|
16
|
+
max_wait: float = 60.0,
|
|
17
|
+
) -> "Space.Message":
|
|
18
|
+
"""
|
|
19
|
+
Sends a prompt asynchronously and polls for completion. (until stoppedStreamingAt is not None)
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
user_id: The user ID.
|
|
23
|
+
company_id: The company ID.
|
|
24
|
+
assistant_id: The assistant ID.
|
|
25
|
+
text: The prompt text.
|
|
26
|
+
poll_interval: Seconds between polls.
|
|
27
|
+
max_wait: Maximum seconds to wait for completion.
|
|
28
|
+
**kwargs: Additional parameters for the prompt.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
The completed Space.Message.
|
|
32
|
+
"""
|
|
33
|
+
# Send the prompt asynchronously
|
|
34
|
+
response = await Space.create_message_async(
|
|
35
|
+
user_id=user_id,
|
|
36
|
+
company_id=company_id,
|
|
37
|
+
assistantId=assistant_id,
|
|
38
|
+
chatId=chat_id,
|
|
39
|
+
text=text,
|
|
40
|
+
toolChoices=tool_choices,
|
|
41
|
+
scopeRules=scope_rules,
|
|
42
|
+
)
|
|
43
|
+
chat_id = response.get("chatId")
|
|
44
|
+
|
|
45
|
+
max_attempts = int(max_wait // poll_interval)
|
|
46
|
+
for _ in range(max_attempts):
|
|
47
|
+
# Poll for the answer
|
|
48
|
+
answer = Space.get_latest_message(user_id, company_id, chat_id)
|
|
49
|
+
if answer.get("stoppedStreamingAt") is not None:
|
|
50
|
+
return answer
|
|
51
|
+
await asyncio.sleep(poll_interval)
|
|
52
|
+
|
|
53
|
+
raise TimeoutError("Timed out waiting for prompt completion.")
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|