unique_sdk 0.10.19__py3-none-any.whl → 0.10.71__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.
Potentially problematic release.
This version of unique_sdk might be problematic. Click here for more details.
- unique_sdk/__init__.py +3 -0
- unique_sdk/api_resources/_agentic_table.py +33 -20
- unique_sdk/api_resources/_content.py +192 -42
- unique_sdk/api_resources/_folder.py +308 -46
- unique_sdk/api_resources/_group.py +429 -0
- unique_sdk/api_resources/_integrated.py +49 -48
- unique_sdk/api_resources/_llm_models.py +64 -0
- unique_sdk/api_resources/_mcp.py +2 -0
- unique_sdk/api_resources/_message.py +96 -3
- unique_sdk/api_resources/_message_execution.py +24 -14
- unique_sdk/api_resources/_message_log.py +46 -19
- unique_sdk/api_resources/_search_string.py +0 -1
- unique_sdk/api_resources/_space.py +387 -8
- unique_sdk/api_resources/_user.py +195 -0
- unique_sdk/utils/chat_in_space.py +30 -28
- unique_sdk/utils/file_io.py +42 -1
- unique_sdk-0.10.71.dist-info/METADATA +389 -0
- {unique_sdk-0.10.19.dist-info → unique_sdk-0.10.71.dist-info}/RECORD +20 -17
- unique_sdk-0.10.19.dist-info/METADATA +0 -1774
- {unique_sdk-0.10.19.dist-info → unique_sdk-0.10.71.dist-info}/LICENSE +0 -0
- {unique_sdk-0.10.19.dist-info → unique_sdk-0.10.71.dist-info}/WHEEL +0 -0
|
@@ -1,1774 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: unique_sdk
|
|
3
|
-
Version: 0.10.19
|
|
4
|
-
Summary:
|
|
5
|
-
License: MIT
|
|
6
|
-
Author: Martin Fadler
|
|
7
|
-
Author-email: martin.fadler@unique.ch
|
|
8
|
-
Requires-Python: >=3.11,<4.0
|
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
-
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
|
14
|
-
Requires-Dist: typing-extensions (>=4.9.0,<5.0.0)
|
|
15
|
-
Description-Content-Type: text/markdown
|
|
16
|
-
|
|
17
|
-
# Unique Python SDK
|
|
18
|
-
|
|
19
|
-
Unique FinanceGPT is a tailored solution for the financial industry, designed to increase productivity by automating manual workloads through AI and ChatGPT solutions.
|
|
20
|
-
|
|
21
|
-
The Unique Python SDK provides access to the public API of Unique FinanceGPT. It also enables verification of Webhook signatures to ensure the authenticity of incoming Webhook requests.
|
|
22
|
-
|
|
23
|
-
## Table of Contents
|
|
24
|
-
|
|
25
|
-
1. [Installation](#installation)
|
|
26
|
-
2. [Requirements](#requirements)
|
|
27
|
-
3. [Usage Instructions](#usage-instructions)
|
|
28
|
-
4. [Webhook Triggers](#webhook-triggers)
|
|
29
|
-
5. [Available API Resources](#available-api-resources)
|
|
30
|
-
- [Content](#content)
|
|
31
|
-
- [Message](#message)
|
|
32
|
-
- [Chat Completion](#chat-completion)
|
|
33
|
-
- [Embeddings](#embeddings)
|
|
34
|
-
- [Acronyms](#acronyms)
|
|
35
|
-
- [Search](#search)
|
|
36
|
-
- [Search String](#search-string)
|
|
37
|
-
- [Short Term Memory](#short-term-memory)
|
|
38
|
-
- [Message Assessment](#message-assessment)
|
|
39
|
-
- [Folder](#folder)
|
|
40
|
-
- [Space](#space)
|
|
41
|
-
6. [UniqueQL](#uniqueql)
|
|
42
|
-
- [Query Structure](#uniqueql-query-structure)
|
|
43
|
-
- [Metadata Filtering](#metadata-filtering)
|
|
44
|
-
7. [Util functions](#utils)
|
|
45
|
-
- [Chat History](#chat-history)
|
|
46
|
-
- [File Io](#file-io)
|
|
47
|
-
- [Sources](#sources)
|
|
48
|
-
- [token](#token)
|
|
49
|
-
- [Chat In Space](#chat-in-space)
|
|
50
|
-
8. [Error Handling](#error-handling)
|
|
51
|
-
9. [Examples](#examples)
|
|
52
|
-
|
|
53
|
-
## Installation
|
|
54
|
-
|
|
55
|
-
Install UniqueSDK and its peer dependency `requests` and when planning to run async requests also `httpx` or `aiohttp` via pip using the following commands:
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
pip install unique_sdk
|
|
59
|
-
pip install requests
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Optional for async requests:
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
pip install httpx
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
or
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
pip install aiohttp
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## Requirements
|
|
75
|
-
|
|
76
|
-
- Python >=3.11 (Other Python versions 3.6+ might work but are not tested)
|
|
77
|
-
- requests (peer dependency. Other HTTP request libraries might be supported in the future)
|
|
78
|
-
- Unique App-ID & API Key
|
|
79
|
-
|
|
80
|
-
Please contact your customer success manager at Unique for your personal developer App-ID & API Key.
|
|
81
|
-
|
|
82
|
-
## Usage instructions
|
|
83
|
-
|
|
84
|
-
The library needs to be configured with your Unique `app_id` & `api_key`. Additionally, each individual request must be scoped to a User and provide a `user_id` & `company_id`.
|
|
85
|
-
|
|
86
|
-
```python
|
|
87
|
-
import unique_sdk
|
|
88
|
-
unique_sdk.api_key = "ukey_..."
|
|
89
|
-
unique_sdk.app_id = "app_..."
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
The SDK includes a set of classes for API resources. Each class contains CRUD methods to interact with the resource.
|
|
93
|
-
|
|
94
|
-
### Example
|
|
95
|
-
|
|
96
|
-
```python
|
|
97
|
-
import unique_sdk
|
|
98
|
-
unique_sdk.api_key = "ukey_..."
|
|
99
|
-
unique_sdk.app_id = "app_..."
|
|
100
|
-
|
|
101
|
-
# list messages for a single chat
|
|
102
|
-
messages = unique_sdk.Message.list(
|
|
103
|
-
user_id=user_id,
|
|
104
|
-
company_id=company_id,
|
|
105
|
-
chatId=chat_id,
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
print(messages.data[0].text)
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
## Webhook Triggers
|
|
112
|
-
|
|
113
|
-
A core functionality of FinanceGPT is the ability for users to engage in an interactive chat feature. SDK developers can hook into this chat to provide new functionalities.
|
|
114
|
-
|
|
115
|
-
Your App (refer to `app-id` in [Requirements](#requirements)) must be subscribed to each individual Unique event in order to receive a webhook.
|
|
116
|
-
|
|
117
|
-
Each webhook sent by Unique includes a set of headers:
|
|
118
|
-
|
|
119
|
-
```yaml
|
|
120
|
-
X-Unique-Id: evt_... # Event id, same as in the body.
|
|
121
|
-
X-Unique-Signature: ... # A HMAC-SHA256 hex signature of the entire body.
|
|
122
|
-
X-Unique-Version: 1.0.0 # Event payload version.
|
|
123
|
-
X-Unique-Created-At: 1705960141 # Unix timestamp (seconds) of the delivery time.
|
|
124
|
-
X-Unique-User-Id: ... # The user who initiated the message.
|
|
125
|
-
X-Unique-Company-Id: ... # The company to which the user belongs.
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Success & Retry on Failure
|
|
129
|
-
|
|
130
|
-
- Webhooks are considered successfully delivered if your endpoint returns a status code between `200` and `299`.
|
|
131
|
-
- If your endpoint returns a status code of `300` - `399`, `429`, or `500` - `599`, Unique will retry the delivery of the webhook with an exponential backoff up to five times.
|
|
132
|
-
- If your endpoint returns any other status (e.g., `404`), it is marked as expired and will not receive any further requests.
|
|
133
|
-
|
|
134
|
-
### Webhook Signature Verification
|
|
135
|
-
|
|
136
|
-
The webhook body, containing a timestamp of the delivery time, is signed with HMAC-SHA256. Verify the signature by constructing the `event` with the `unique_sdk.Webhook` class:
|
|
137
|
-
|
|
138
|
-
```python
|
|
139
|
-
from http import HTTPStatus
|
|
140
|
-
from flask import Flask, jsonify, request
|
|
141
|
-
import unique_sdk
|
|
142
|
-
|
|
143
|
-
endpoint_secret = "YOUR_ENDPOINT_SECRET"
|
|
144
|
-
|
|
145
|
-
@app.route("/webhook", methods=["POST"])
|
|
146
|
-
def webhook():
|
|
147
|
-
event = None
|
|
148
|
-
payload = request.data
|
|
149
|
-
|
|
150
|
-
sig_header = request.headers.get("X-Unique-Signature")
|
|
151
|
-
timestamp = request.headers.get("X-Unique-Created-At")
|
|
152
|
-
|
|
153
|
-
if not sig_header or not timestamp:
|
|
154
|
-
print("⚠️ Webhook signature or timestamp headers missing.")
|
|
155
|
-
return jsonify(success=False), HTTPStatus.BAD_REQUEST
|
|
156
|
-
|
|
157
|
-
try:
|
|
158
|
-
event = unique_sdk.Webhook.construct_event(
|
|
159
|
-
payload, sig_header, timestamp, endpoint_secret
|
|
160
|
-
)
|
|
161
|
-
except unique_sdk.SignatureVerificationError as e:
|
|
162
|
-
print("⚠️ Webhook signature verification failed. " + str(e))
|
|
163
|
-
return jsonify(success=False), HTTPStatus.BAD_REQUEST
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
The `construct_event` method will compare the signature and raise a `unique_sdk.SignatureVerificationError` if the signature does not match. It will also raise this error if the `createdAt` timestamp is outside of a default tolerance of 5 minutes. Adjust the `tolerance` by passing a fifth parameter to the method (tolerance in seconds), e.g.:
|
|
167
|
-
|
|
168
|
-
```python
|
|
169
|
-
event = unique_sdk.Webhook.construct_event(
|
|
170
|
-
payload, sig_header, timestamp, endpoint_secret, 0
|
|
171
|
-
)
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
### Available Unique Events
|
|
175
|
-
|
|
176
|
-
#### User Message Created
|
|
177
|
-
|
|
178
|
-
```json
|
|
179
|
-
{
|
|
180
|
-
"id": "evt_...", // see header
|
|
181
|
-
"version": "1.0.0", // see header
|
|
182
|
-
"event": "unique.chat.user-message.created", // The name of the event
|
|
183
|
-
"createdAt": "1705960141", // see header
|
|
184
|
-
"userId": "...", // see header
|
|
185
|
-
"companyId": "...", // see header
|
|
186
|
-
"payload": {
|
|
187
|
-
"chatId": "chat_...", // The id of the chat
|
|
188
|
-
"assistantId": "assistant_...", // The id of the selected assistant
|
|
189
|
-
"text": "Hello, how can I help you?" // The user message
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
This webhook is triggered for every new chat message sent by the user. This event occurs regardless of whether it is the first or a subsequent message in a chat. Use the `unique_sdk.Message` class to retrieve other messages from the same `chatId` or maintain a local state of the messages in a single chat.
|
|
195
|
-
|
|
196
|
-
This trigger can be used in combination with assistants marked as `external`. Those assistants will not execute any logic, enabling your code to respond to the user message and create an answer.
|
|
197
|
-
|
|
198
|
-
#### External Module Chosen
|
|
199
|
-
|
|
200
|
-
```json
|
|
201
|
-
{
|
|
202
|
-
"id": "evt_...",
|
|
203
|
-
"version": "1.0.0",
|
|
204
|
-
"event": "unique.chat.external-module.chosen",
|
|
205
|
-
"createdAt": "1705960141", // Unix timestamp (seconds)
|
|
206
|
-
"userId": "...",
|
|
207
|
-
"companyId": "...",
|
|
208
|
-
"payload": {
|
|
209
|
-
"name": "example-sdk", // The name of the module selected by the module chooser
|
|
210
|
-
"description": "Example SDK", // The description of the module
|
|
211
|
-
"configuration": {}, // Module configuration in JSON format
|
|
212
|
-
"chatid": "chat_...", // The chat ID
|
|
213
|
-
"assistantId:": "assistant_...", // The assistant ID
|
|
214
|
-
"userMessage": {
|
|
215
|
-
"id": "msg_...",
|
|
216
|
-
"text": "Hello World!", // The user message leading to the module selection
|
|
217
|
-
"createdAt": "2024-01-01T00:00:00.000Z" // ISO 8601
|
|
218
|
-
},
|
|
219
|
-
"assistantMessage": {
|
|
220
|
-
"id": "msg_...",
|
|
221
|
-
"createdAt": "2024-01-01T00:00:00.000Z" // ISO 8601
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
This Webhook is triggered when the Unique FinanceGPT AI selects an external module as the best response to a user message. The module must be marked as `external` and available for the assistant used in the chat to be selected by the AI.
|
|
228
|
-
|
|
229
|
-
Unique's UI will create an empty `assistantMessage` below the user message and update this message with status updates.
|
|
230
|
-
|
|
231
|
-
**The SDK is expected to modify this assistantMessage with its answer to the user message.**
|
|
232
|
-
|
|
233
|
-
```python
|
|
234
|
-
unique_sdk.Message.modify(
|
|
235
|
-
user_id=user_id,
|
|
236
|
-
company_id=company_id,
|
|
237
|
-
id=assistant_message_id,
|
|
238
|
-
chatId=chat_id,
|
|
239
|
-
text="Here is your answer.",
|
|
240
|
-
)
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
## Available API Resources
|
|
244
|
-
|
|
245
|
-
- [Content](#content)
|
|
246
|
-
- [Message](#message)
|
|
247
|
-
- [Chat Completion](#chat-completion)
|
|
248
|
-
- [Embeddings](#embeddings)
|
|
249
|
-
- [Acronyms](#acronyms)
|
|
250
|
-
- [Search](#search)
|
|
251
|
-
- [Search String](#search-string)
|
|
252
|
-
- [Short Term Memory](#short-term-memory)
|
|
253
|
-
- [Message Assessment](#message-assessment)
|
|
254
|
-
- [Folder](#folder)
|
|
255
|
-
- [Space](#space)
|
|
256
|
-
|
|
257
|
-
Most of the API services provide an asynchronous version of the method. The async methods are suffixed with `_async`.
|
|
258
|
-
|
|
259
|
-
### Content
|
|
260
|
-
|
|
261
|
-
#### `unique_sdk.Content.search`
|
|
262
|
-
|
|
263
|
-
Allows you to load full content/files from the knowledge-base of unique with the rights of the userId and companyId. Provided a `where` query for filtering. Filtering can be done on any of the following fields: `
|
|
264
|
-
|
|
265
|
-
- `id`
|
|
266
|
-
- `key`
|
|
267
|
-
- `ownerId`
|
|
268
|
-
- `title`
|
|
269
|
-
- `url`
|
|
270
|
-
|
|
271
|
-
Here an example of retrieving all files that contain the number 42 in the `title` or the `key` typically this is used to search by filename.
|
|
272
|
-
|
|
273
|
-
```python
|
|
274
|
-
unique_sdk.Content.search(
|
|
275
|
-
user_id=userId,
|
|
276
|
-
company_id=companyId,
|
|
277
|
-
where={
|
|
278
|
-
"OR": [
|
|
279
|
-
{
|
|
280
|
-
"title": {
|
|
281
|
-
"contains": "42",
|
|
282
|
-
},
|
|
283
|
-
},
|
|
284
|
-
{
|
|
285
|
-
"key": {
|
|
286
|
-
"contains": "42",
|
|
287
|
-
},
|
|
288
|
-
},
|
|
289
|
-
],
|
|
290
|
-
},
|
|
291
|
-
chatId=chatId,
|
|
292
|
-
)
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
#### `unique_sdk.Content.get_info`
|
|
296
|
-
|
|
297
|
-
[Deprecated, use `unique_sdk.Content.get_infos` instead.] 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:
|
|
298
|
-
|
|
299
|
-
```python
|
|
300
|
-
metadataFilter: {
|
|
301
|
-
"or": [
|
|
302
|
-
{
|
|
303
|
-
"and": [
|
|
304
|
-
{
|
|
305
|
-
"operator": "contains",
|
|
306
|
-
"path": [
|
|
307
|
-
"folderIdPath"
|
|
308
|
-
],
|
|
309
|
-
"value": "uniquepathid://test_id"
|
|
310
|
-
},
|
|
311
|
-
{
|
|
312
|
-
"operator": "contains",
|
|
313
|
-
"path": [
|
|
314
|
-
"title"
|
|
315
|
-
],
|
|
316
|
-
"value": "ai"
|
|
317
|
-
}
|
|
318
|
-
]
|
|
319
|
-
}
|
|
320
|
-
]
|
|
321
|
-
},
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
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:`
|
|
325
|
-
|
|
326
|
-
- `skip`
|
|
327
|
-
- `take`
|
|
328
|
-
|
|
329
|
-
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 `title` metadata.
|
|
330
|
-
|
|
331
|
-
```python
|
|
332
|
-
content_info_result = unique_sdk.Content.get_info(
|
|
333
|
-
user_id=user_id,
|
|
334
|
-
company_id=company_id,
|
|
335
|
-
metadataFilter={
|
|
336
|
-
"or": [
|
|
337
|
-
{
|
|
338
|
-
"and": [
|
|
339
|
-
{
|
|
340
|
-
"operator": "contains",
|
|
341
|
-
"path": [
|
|
342
|
-
"folderIdPath"
|
|
343
|
-
],
|
|
344
|
-
"value": "uniquepathid://scope_abcdibgznc4bkdcx120zm5d"
|
|
345
|
-
},
|
|
346
|
-
{
|
|
347
|
-
"operator": "contains",
|
|
348
|
-
"path": [
|
|
349
|
-
"title"
|
|
350
|
-
],
|
|
351
|
-
"value": "ai"
|
|
352
|
-
}
|
|
353
|
-
]
|
|
354
|
-
}
|
|
355
|
-
]
|
|
356
|
-
},
|
|
357
|
-
skip=0,
|
|
358
|
-
take=3,
|
|
359
|
-
)
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
#### `unique_sdk.Content.get_infos`
|
|
363
|
-
|
|
364
|
-
Allows you to get content infos. To filter the results you can define a either metadata filter in UniqueQL language or specify a parentId. If both are defined, the function will throw an error.
|
|
365
|
-
|
|
366
|
-
I f you want to learn more about UniqueQL, you can find out more about it in the [UniqueQL](#uniqueql) section. An example of a metadata filter defined with UniqueQL is the following:
|
|
367
|
-
|
|
368
|
-
```python
|
|
369
|
-
metadataFilter: {
|
|
370
|
-
"or": [
|
|
371
|
-
{
|
|
372
|
-
"and": [
|
|
373
|
-
{
|
|
374
|
-
"operator": "contains",
|
|
375
|
-
"path": [
|
|
376
|
-
"folderIdPath"
|
|
377
|
-
],
|
|
378
|
-
"value": "uniquepathid://test_id"
|
|
379
|
-
},
|
|
380
|
-
{
|
|
381
|
-
"operator": "contains",
|
|
382
|
-
"path": [
|
|
383
|
-
"title"
|
|
384
|
-
],
|
|
385
|
-
"value": "ai"
|
|
386
|
-
}
|
|
387
|
-
]
|
|
388
|
-
}
|
|
389
|
-
]
|
|
390
|
-
},
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
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:`
|
|
394
|
-
|
|
395
|
-
- `skip`
|
|
396
|
-
- `take`
|
|
397
|
-
|
|
398
|
-
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 `title` metadata.
|
|
399
|
-
|
|
400
|
-
```python
|
|
401
|
-
content_info_result = unique_sdk.Content.get_infos(
|
|
402
|
-
user_id=user_id,
|
|
403
|
-
company_id=company_id,
|
|
404
|
-
metadataFilter={
|
|
405
|
-
"or": [
|
|
406
|
-
{
|
|
407
|
-
"and": [
|
|
408
|
-
{
|
|
409
|
-
"operator": "contains",
|
|
410
|
-
"path": [
|
|
411
|
-
"folderIdPath"
|
|
412
|
-
],
|
|
413
|
-
"value": "uniquepathid://scope_abcdibgznc4bkdcx120zm5d"
|
|
414
|
-
},
|
|
415
|
-
{
|
|
416
|
-
"operator": "contains",
|
|
417
|
-
"path": [
|
|
418
|
-
"title"
|
|
419
|
-
],
|
|
420
|
-
"value": "ai"
|
|
421
|
-
}
|
|
422
|
-
]
|
|
423
|
-
}
|
|
424
|
-
]
|
|
425
|
-
},
|
|
426
|
-
skip=0,
|
|
427
|
-
take=3,
|
|
428
|
-
)
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
Here is an example of retrieving the contents based on a parentId.
|
|
432
|
-
|
|
433
|
-
```python
|
|
434
|
-
content_info_result = unique_sdk.Content.get_infos(
|
|
435
|
-
user_id=user_id,
|
|
436
|
-
company_id=company_id,
|
|
437
|
-
parentId="scope_ahefgj389srjbfejkkk98u"
|
|
438
|
-
)
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
#### `unique_sdk.Content.upsert`
|
|
442
|
-
|
|
443
|
-
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.
|
|
444
|
-
|
|
445
|
-
Typical usage is the following. That creates a Content and uploads a file
|
|
446
|
-
|
|
447
|
-
```python
|
|
448
|
-
|
|
449
|
-
createdContent = upload_file(
|
|
450
|
-
userId,
|
|
451
|
-
companyId,
|
|
452
|
-
"/path/to/file.pdf",
|
|
453
|
-
"test.pdf",
|
|
454
|
-
"application/pdf",
|
|
455
|
-
"scope_stcj2osgbl722m22jayidx0n",
|
|
456
|
-
ingestionConfig={
|
|
457
|
-
"chunkMaxTokens": 1000,
|
|
458
|
-
"chunkStrategy": "default",
|
|
459
|
-
"uniqueIngestionMode": "standard",
|
|
460
|
-
},
|
|
461
|
-
metadata={
|
|
462
|
-
"folderIdPath": "uniquepathid://scope_id"
|
|
463
|
-
}
|
|
464
|
-
)
|
|
465
|
-
|
|
466
|
-
def upload_file(
|
|
467
|
-
userId,
|
|
468
|
-
companyId,
|
|
469
|
-
path_to_file,
|
|
470
|
-
displayed_filename,
|
|
471
|
-
mimeType,
|
|
472
|
-
scope_or_unique_path,
|
|
473
|
-
ingestion_config=None,
|
|
474
|
-
metadata=None,
|
|
475
|
-
):
|
|
476
|
-
size = os.path.getsize(path_to_file)
|
|
477
|
-
createdContent = unique_sdk.Content.upsert(
|
|
478
|
-
user_id=userId,
|
|
479
|
-
company_id=companyId,
|
|
480
|
-
input={
|
|
481
|
-
"key": displayed_filename,
|
|
482
|
-
"title": displayed_filename,
|
|
483
|
-
"mimeType": mimeType,
|
|
484
|
-
"ingestionConfig": ingestionConfig,
|
|
485
|
-
"metadata": metadata,
|
|
486
|
-
},
|
|
487
|
-
scopeId=scope_or_unique_path,
|
|
488
|
-
)
|
|
489
|
-
|
|
490
|
-
uploadUrl = createdContent.writeUrl
|
|
491
|
-
|
|
492
|
-
# upload to azure blob storage SAS url uploadUrl the pdf file translatedFile make sure it is treated as a application/pdf
|
|
493
|
-
with open(path_to_file, "rb") as file:
|
|
494
|
-
requests.put(
|
|
495
|
-
uploadUrl,
|
|
496
|
-
data=file,
|
|
497
|
-
headers={
|
|
498
|
-
"X-Ms-Blob-Content-Type": mimeType,
|
|
499
|
-
"X-Ms-Blob-Type": "BlockBlob",
|
|
500
|
-
},
|
|
501
|
-
)
|
|
502
|
-
|
|
503
|
-
unique_sdk.Content.upsert(
|
|
504
|
-
user_id=userId,
|
|
505
|
-
company_id=companyId,
|
|
506
|
-
input={
|
|
507
|
-
"key": displayed_filename,
|
|
508
|
-
"title": displayed_filename,
|
|
509
|
-
"mimeType": mimeType,
|
|
510
|
-
"byteSize": size,
|
|
511
|
-
"ingestionConfig": ingestionConfig,
|
|
512
|
-
"metadata": metadata,
|
|
513
|
-
},
|
|
514
|
-
scopeId=scope_or_unique_path,
|
|
515
|
-
readUrl=createdContent.readUrl,
|
|
516
|
-
)
|
|
517
|
-
|
|
518
|
-
return createdContent
|
|
519
|
-
|
|
520
|
-
```
|
|
521
|
-
|
|
522
|
-
#### `unique_sdk.Content.ingest_magic_table_sheets`
|
|
523
|
-
|
|
524
|
-
Allows you to ingest a magic table sheet, each row is processed and converted into a content.
|
|
525
|
-
```python
|
|
526
|
-
params = {
|
|
527
|
-
"user_id": user_id,
|
|
528
|
-
"company_id": company_id,
|
|
529
|
-
"data": [
|
|
530
|
-
{
|
|
531
|
-
"rowId": "2",
|
|
532
|
-
"columns": [
|
|
533
|
-
{"columnId": "0", "columnName": "Section", "content": "Other"},
|
|
534
|
-
{"columnId": "1", "columnName": "Question", "content": "What do you know?"},
|
|
535
|
-
{
|
|
536
|
-
"columnId": "2",
|
|
537
|
-
"columnName": "Knowledge Base Answer",
|
|
538
|
-
"content": "Lorem Ipsum is simply dummy texktop publishing software.",
|
|
539
|
-
},
|
|
540
|
-
],
|
|
541
|
-
},
|
|
542
|
-
],
|
|
543
|
-
"ingestionConfiguration": {
|
|
544
|
-
"columnIdsInMetadata": ["1", "2"],
|
|
545
|
-
"columnIdsInChunkText": ["1", "2"],
|
|
546
|
-
},
|
|
547
|
-
"metadata": {
|
|
548
|
-
"libraryName": "foo",
|
|
549
|
-
},
|
|
550
|
-
"scopeId": scope_id,
|
|
551
|
-
"sheetName": "Sheet1",
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
unique_sdk.Content.ingest_magic_table_sheets(**params)
|
|
555
|
-
```
|
|
556
|
-
|
|
557
|
-
#### `unique_sdk.Content.update` (Compatible with release >.36)
|
|
558
|
-
|
|
559
|
-
Allows you to update a file specified by its `contentId`.
|
|
560
|
-
|
|
561
|
-
- `contentId` the id of the file to be updated
|
|
562
|
-
|
|
563
|
-
Currently, the following updates are supported:
|
|
564
|
-
|
|
565
|
-
Title update:
|
|
566
|
-
- `title` optional, allows updating the title of the folder
|
|
567
|
-
|
|
568
|
-
Move the file to a different folder. this can be done by specifying either the `ownerId`.
|
|
569
|
-
- `ownerId` optional, allows moving the file to a different folder. Represents the new folder for the file and it should be the id of a folder e.g.: `scope_dhjfieurfloakmdle`.
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
Example of moving a file specified by its content id.
|
|
573
|
-
|
|
574
|
-
```python
|
|
575
|
-
unique_sdk.Content.update(
|
|
576
|
-
user_id=user_id,
|
|
577
|
-
company_id=company_id,
|
|
578
|
-
contentId="cont_ok2343q5owbce80w78hudawu5",
|
|
579
|
-
ownerId="scope_e68yz5asho7glfh7c7d041el"
|
|
580
|
-
)
|
|
581
|
-
```
|
|
582
|
-
|
|
583
|
-
Example of moving a file and updating its title.
|
|
584
|
-
|
|
585
|
-
```python
|
|
586
|
-
unique_sdk.Content.update(
|
|
587
|
-
user_id=user_id,
|
|
588
|
-
company_id=company_id,
|
|
589
|
-
contentId="cont_ok2343q5owbce80w78hudawu5",
|
|
590
|
-
ownerId="scope_e68yz5asho7glfh7c7d041el",
|
|
591
|
-
title="Revision Deck (1)"
|
|
592
|
-
)
|
|
593
|
-
```
|
|
594
|
-
|
|
595
|
-
#### `unique_sdk.Content.delete` (Compatible with release >.36)
|
|
596
|
-
|
|
597
|
-
Allows you to delete a file by its `contentId`. If the file is part of a chat, the `chatId` also needs do be set.
|
|
598
|
-
|
|
599
|
-
- `contentId` the id of the file to be deleted
|
|
600
|
-
- `chatId` optional, the id of the chat where the file is. Only needed if the file is part of a chat
|
|
601
|
-
|
|
602
|
-
Example of deleting a file from a chat.
|
|
603
|
-
|
|
604
|
-
```python
|
|
605
|
-
unique_sdk.Content.delete(
|
|
606
|
-
user_id=user_id,
|
|
607
|
-
company_id=company_id,
|
|
608
|
-
contentId="cont_ok2343q5owbce80w78hudawu5",
|
|
609
|
-
chatId="chat_v3xfa7liv876h89vuiibus1"
|
|
610
|
-
)
|
|
611
|
-
```
|
|
612
|
-
|
|
613
|
-
### Message
|
|
614
|
-
|
|
615
|
-
#### `unique_sdk.Message.list`
|
|
616
|
-
|
|
617
|
-
Retrieve a list of messages for a provided `chatId`.
|
|
618
|
-
|
|
619
|
-
```python
|
|
620
|
-
messages = unique_sdk.Message.list(
|
|
621
|
-
user_id=user_id,
|
|
622
|
-
company_id=company_id,
|
|
623
|
-
chatId=chat_id,
|
|
624
|
-
)
|
|
625
|
-
```
|
|
626
|
-
|
|
627
|
-
#### `unique_sdk.Message.retrieve`
|
|
628
|
-
|
|
629
|
-
Get a single chat message.
|
|
630
|
-
|
|
631
|
-
```python
|
|
632
|
-
message = unique_sdk.Message.retrieve(
|
|
633
|
-
user_id=user_id,
|
|
634
|
-
company_id=company_id,
|
|
635
|
-
id=message_id,
|
|
636
|
-
chatId=chat_id,
|
|
637
|
-
)
|
|
638
|
-
```
|
|
639
|
-
|
|
640
|
-
#### `unique_sdk.Message.create`
|
|
641
|
-
|
|
642
|
-
Create a new message in a chat.
|
|
643
|
-
|
|
644
|
-
```python
|
|
645
|
-
message = unique_sdk.Message.create(
|
|
646
|
-
user_id=user_id,
|
|
647
|
-
company_id=company_id,
|
|
648
|
-
chatId=chat_id,
|
|
649
|
-
assistantId=assistant_id,
|
|
650
|
-
text="Hello.",
|
|
651
|
-
role="ASSISTANT",
|
|
652
|
-
)
|
|
653
|
-
```
|
|
654
|
-
|
|
655
|
-
#### `unique_sdk.Message.modify`
|
|
656
|
-
|
|
657
|
-
Modify an existing chat message.
|
|
658
|
-
|
|
659
|
-
ℹ️ if you modify the debugInfo only do it on the user message as this is the only place that is displayed in the frontend.
|
|
660
|
-
|
|
661
|
-
```python
|
|
662
|
-
message = unique_sdk.Message.modify(
|
|
663
|
-
user_id=user_id,
|
|
664
|
-
company_id=company_id,
|
|
665
|
-
id=message_id,
|
|
666
|
-
chatId=chat_id,
|
|
667
|
-
text="Updated message text"
|
|
668
|
-
)
|
|
669
|
-
```
|
|
670
|
-
|
|
671
|
-
#### `unique_sdk.Message.delete`
|
|
672
|
-
|
|
673
|
-
Delete a chat message.
|
|
674
|
-
|
|
675
|
-
```python
|
|
676
|
-
message = unique_sdk.Message.delete(
|
|
677
|
-
message_id,
|
|
678
|
-
user_id=user_id,
|
|
679
|
-
company_id=company_id,
|
|
680
|
-
chatId=chat_id,
|
|
681
|
-
)
|
|
682
|
-
```
|
|
683
|
-
|
|
684
|
-
#### `unique_sdk.Integrated.stream`
|
|
685
|
-
|
|
686
|
-
Streams the answer to the chat frontend. Given the messages.
|
|
687
|
-
|
|
688
|
-
if the stream creates [source0] it is referenced with the references from the search context.
|
|
689
|
-
|
|
690
|
-
E.g.
|
|
691
|
-
|
|
692
|
-
```
|
|
693
|
-
Hello this information is from [srouce1]
|
|
694
|
-
```
|
|
695
|
-
|
|
696
|
-
adds the reference at index 1 and then changes the text to:
|
|
697
|
-
|
|
698
|
-
```
|
|
699
|
-
Hello this information is from <sub>0</sub>
|
|
700
|
-
```
|
|
701
|
-
|
|
702
|
-
```python
|
|
703
|
-
unique_sdk.Integrated.chat_stream_completion(
|
|
704
|
-
user_id=userId,
|
|
705
|
-
company_id=companyId,
|
|
706
|
-
assistantMessageId=assistantMessageId,
|
|
707
|
-
userMessageId=userMessageId,
|
|
708
|
-
messages=[
|
|
709
|
-
{
|
|
710
|
-
"role": "system",
|
|
711
|
-
"content": "be friendly and helpful"
|
|
712
|
-
},
|
|
713
|
-
{
|
|
714
|
-
"role": "user",
|
|
715
|
-
"content": "hello"
|
|
716
|
-
}
|
|
717
|
-
],
|
|
718
|
-
chatId=chatId,
|
|
719
|
-
|
|
720
|
-
searchContext= [
|
|
721
|
-
{
|
|
722
|
-
"id": "ref_qavsg0dcl5cbfwm1fvgogrvo",
|
|
723
|
-
"chunkId": "0",
|
|
724
|
-
"key": "some reference.pdf : 8,9,10,11",
|
|
725
|
-
"sequenceNumber": 1,
|
|
726
|
-
"url": "unique://content/cont_p8n339trfsf99oc9f36rn4wf"
|
|
727
|
-
}
|
|
728
|
-
], # optional
|
|
729
|
-
debugInfo={
|
|
730
|
-
"hello": "test"
|
|
731
|
-
}, # optional
|
|
732
|
-
startText= "I want to tell you about: ", # optional
|
|
733
|
-
model= "AZURE_GPT_4_32K_0613", # optional
|
|
734
|
-
timeout=8000, # optional in ms
|
|
735
|
-
options={
|
|
736
|
-
"temperature": 0.5
|
|
737
|
-
} # optional
|
|
738
|
-
)
|
|
739
|
-
```
|
|
740
|
-
|
|
741
|
-
**Warning:** Currently, the deletion of a chat message does not automatically sync with the user UI. Users must refresh the chat page to view the updated state. This issue will be addressed in a future update of our API.
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
#### `unique_sdk.Integrated.responses_stream`
|
|
745
|
-
|
|
746
|
-
Streams the answer to the chat frontend using the Responses API. Given the messages.
|
|
747
|
-
|
|
748
|
-
if the stream creates [source0] it is referenced with the references from the search context.
|
|
749
|
-
|
|
750
|
-
E.g.
|
|
751
|
-
|
|
752
|
-
```
|
|
753
|
-
Hello this information is from [source1]
|
|
754
|
-
```
|
|
755
|
-
|
|
756
|
-
adds the reference at index 1 and then changes the text to:
|
|
757
|
-
|
|
758
|
-
```
|
|
759
|
-
Hello this information is from <sub>0</sub>
|
|
760
|
-
```
|
|
761
|
-
|
|
762
|
-
```python
|
|
763
|
-
unique_sdk.Integrated.responses_stream(
|
|
764
|
-
user_id=userId,
|
|
765
|
-
company_id=companyId,
|
|
766
|
-
model="AZURE_o3_2025_0416",
|
|
767
|
-
assistantMessageId=assistantMessageId,
|
|
768
|
-
userMessageId=userMessageId,
|
|
769
|
-
input="Tell me about the curious case of neural text degeneration",
|
|
770
|
-
chatId=chatId,
|
|
771
|
-
)
|
|
772
|
-
```
|
|
773
|
-
|
|
774
|
-
**Warning:** Currently, the deletion of a chat message does not automatically sync with the user UI. Users must refresh the chat page to view the updated state. This issue will be addressed in a future update of our API.
|
|
775
|
-
|
|
776
|
-
### Chat Completion
|
|
777
|
-
|
|
778
|
-
#### `unique_sdk.ChatCompletion.create`
|
|
779
|
-
|
|
780
|
-
Send a prompt to an AI model supported by Unique FinanceGPT and receive a result. The `messages` attribute must follow the [OpenAI API format](https://platform.openai.com/docs/api-reference/chat).
|
|
781
|
-
|
|
782
|
-
```python
|
|
783
|
-
chat_completion = unique_sdk.ChatCompletion.create(
|
|
784
|
-
company_id=company_id,
|
|
785
|
-
user_id=user_id
|
|
786
|
-
model="AZURE_GPT_35_TURBO",
|
|
787
|
-
messages=[
|
|
788
|
-
{"role": "system", "content": "You are a helpful assistant."},
|
|
789
|
-
{"role": "user", "content": "Hello!"},
|
|
790
|
-
],
|
|
791
|
-
options={
|
|
792
|
-
"temperature": 0.5
|
|
793
|
-
} # optional
|
|
794
|
-
)
|
|
795
|
-
```
|
|
796
|
-
|
|
797
|
-
### Embeddings
|
|
798
|
-
|
|
799
|
-
#### `unique_sdk.Embeddings.create`
|
|
800
|
-
|
|
801
|
-
Sends an array of `text` to the AI model for embedding. And retrieve a vector of embeddings.
|
|
802
|
-
|
|
803
|
-
```python
|
|
804
|
-
result = unique_sdk.Embeddings.create(
|
|
805
|
-
user_id=user_id,
|
|
806
|
-
company_id=company_id,
|
|
807
|
-
texts=["hello", "hello"],
|
|
808
|
-
)
|
|
809
|
-
print(result.embeddings[0][0])
|
|
810
|
-
```
|
|
811
|
-
|
|
812
|
-
### Acronyms
|
|
813
|
-
|
|
814
|
-
#### `unique_sdk.Acronyms.get`
|
|
815
|
-
|
|
816
|
-
Fetches the acronyms defined on the company. Often used to replace in user prompts, so the acronym is resolved to give better guidance to the LLM during completion.
|
|
817
|
-
|
|
818
|
-
```python
|
|
819
|
-
result = unique_sdk.Acronyms.get(
|
|
820
|
-
user_id=user_id,
|
|
821
|
-
company_id=company_id,
|
|
822
|
-
)
|
|
823
|
-
print(result)
|
|
824
|
-
```
|
|
825
|
-
|
|
826
|
-
### Search
|
|
827
|
-
|
|
828
|
-
#### `unique_sdk.Search.create`
|
|
829
|
-
|
|
830
|
-
Search the Unique FinanceGPT Knowledge database for RAG (Retrieval-Augmented Generation). The API supports vector search and a `searchType` that combines vector and full-text search, enhancing the precision of search results.
|
|
831
|
-
|
|
832
|
-
These are the options are available for `searchType`:
|
|
833
|
-
|
|
834
|
-
- `VECTOR`
|
|
835
|
-
- `COMBINED`
|
|
836
|
-
|
|
837
|
-
`limit` (max 1000) and `page` are optional for iterating over results.
|
|
838
|
-
`chatOnly` Restricts the search exclusively to documents uploaded within the chat.
|
|
839
|
-
`scopeIds` Specifies a collection of scope IDs to confine the search.
|
|
840
|
-
`language` Optional. The language specification for full text search.
|
|
841
|
-
`reranker` Optional. The reranker service to be used for re-ranking the search results.
|
|
842
|
-
`chatId` Optional, adds the documents uploaded in this chat to the scope of searched documents.
|
|
843
|
-
`scoreThreshold` Optional, sets the minimum similarity score for search results to be considered. Using 0 is recommended.
|
|
844
|
-
|
|
845
|
-
```python
|
|
846
|
-
search = unique_sdk.Search.create(
|
|
847
|
-
user_id=user_id,
|
|
848
|
-
company_id=company_id,
|
|
849
|
-
chatId=chat_id
|
|
850
|
-
searchString="What is the meaning of life, the universe and everything?",
|
|
851
|
-
searchType="VECTOR",
|
|
852
|
-
chatOnly=false,
|
|
853
|
-
scopeIds=["scope_..."],
|
|
854
|
-
language="German",
|
|
855
|
-
reranker={"deploymentName": "my_deployment"},
|
|
856
|
-
limit=20,
|
|
857
|
-
page=1
|
|
858
|
-
scoreThreshold=0
|
|
859
|
-
)
|
|
860
|
-
```
|
|
861
|
-
|
|
862
|
-
### Search String
|
|
863
|
-
|
|
864
|
-
#### `unique_sdk.SearchString.create`
|
|
865
|
-
|
|
866
|
-
User messages are sometimes suboptimal as input prompts for vector or full-text knowledge base searches. This is particularly true as a conversation progresses and a user question may lack crucial context for a successful search.
|
|
867
|
-
|
|
868
|
-
This API transforms and translates (into English) the user's message into an ideal search string for use in the [Search.create](#unique_sdksearchcreate) API method.
|
|
869
|
-
|
|
870
|
-
Adding a `chatId` or `messages` as arguments allows the message history to provide additional context to the search string. For example, "Who is the author?" will be expanded to "Who is the author of the book 'The Hitchhiker's Guide to the Galaxy'?" if previous messages referenced the book.
|
|
871
|
-
|
|
872
|
-
```python
|
|
873
|
-
search_string = unique_sdk.SearchString.create(
|
|
874
|
-
user_id=user_id,
|
|
875
|
-
company_id=company_id,
|
|
876
|
-
prompt="Was ist der Sinn des Lebens, des Universums und des ganzen Rests?",
|
|
877
|
-
chat_id=chat_id
|
|
878
|
-
)
|
|
879
|
-
```
|
|
880
|
-
|
|
881
|
-
### Short Term Memory
|
|
882
|
-
|
|
883
|
-
For saving data in between chats there is the Short Term Memory functionality to save small data in between rounds of chat e.g. language, search results and so on.
|
|
884
|
-
For this 10k chars can be used. You can save a short term memory for a chat `chatId` or for a message `messageId`.
|
|
885
|
-
you need to provide an `memoryName` as an identifier.
|
|
886
|
-
|
|
887
|
-
you can then save it and retreive it live defined below.
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
#### `unique_sdk.ShortTermMemory.create`
|
|
891
|
-
|
|
892
|
-
```python
|
|
893
|
-
c = unique_sdk.ShortTermMemory.create(
|
|
894
|
-
user_id=user_id,
|
|
895
|
-
company_id=company_id,
|
|
896
|
-
data="hello",
|
|
897
|
-
chatId="chat_x0xxtj89f7drjp4vmued3q",
|
|
898
|
-
# messageId = "msg_id",
|
|
899
|
-
memoryName="your memory name",
|
|
900
|
-
)
|
|
901
|
-
print(c)
|
|
902
|
-
```
|
|
903
|
-
|
|
904
|
-
#### `unique_sdk.ShortTermMemory.find-latest`
|
|
905
|
-
|
|
906
|
-
```python
|
|
907
|
-
m = unique_sdk.ShortTermMemory.find_latest(
|
|
908
|
-
user_id=user_id,
|
|
909
|
-
company_id=company_id,
|
|
910
|
-
chatId="chat_x0xxtj89f7drjp4vmued3q",
|
|
911
|
-
# messageId = "msg_id",
|
|
912
|
-
memoryName="your memory name",
|
|
913
|
-
)
|
|
914
|
-
print(m)
|
|
915
|
-
```
|
|
916
|
-
|
|
917
|
-
### Message Assessment
|
|
918
|
-
|
|
919
|
-
Used to create and modify message assessments for tracking hallucinations and compliance evaluations of assistant messages.
|
|
920
|
-
|
|
921
|
-
#### `unique_sdk.MessageAssessment.create`
|
|
922
|
-
|
|
923
|
-
Create a new message assessment for an assistant message.
|
|
924
|
-
|
|
925
|
-
```python
|
|
926
|
-
assessment = unique_sdk.MessageAssessment.create(
|
|
927
|
-
user_id=user_id,
|
|
928
|
-
company_id=company_id,
|
|
929
|
-
assistant_message_id="msg_...",
|
|
930
|
-
status="DONE",
|
|
931
|
-
explanation="This response contains incorrect information about...",
|
|
932
|
-
label="RED",
|
|
933
|
-
type="HALLUCINATION",
|
|
934
|
-
title="Hallucination detected",
|
|
935
|
-
isVisible=True
|
|
936
|
-
)
|
|
937
|
-
```
|
|
938
|
-
|
|
939
|
-
#### `unique_sdk.MessageAssessment.modify`
|
|
940
|
-
|
|
941
|
-
Modify an existing message assessment.
|
|
942
|
-
|
|
943
|
-
```python
|
|
944
|
-
assessment = unique_sdk.MessageAssessment.modify(
|
|
945
|
-
user_id=user_id,
|
|
946
|
-
company_id=company_id,
|
|
947
|
-
assistant_message_id="msg_...",
|
|
948
|
-
status="DONE",
|
|
949
|
-
explanation="Updated explanation...",
|
|
950
|
-
label="RED",
|
|
951
|
-
title="update title"
|
|
952
|
-
type="HALLUCINATION"
|
|
953
|
-
)
|
|
954
|
-
```
|
|
955
|
-
|
|
956
|
-
### Folder
|
|
957
|
-
|
|
958
|
-
#### `unique_sdk.Folder.get_info`
|
|
959
|
-
|
|
960
|
-
Get a folder by scope id or by path.
|
|
961
|
-
|
|
962
|
-
By scope id:
|
|
963
|
-
|
|
964
|
-
```python
|
|
965
|
-
unique_sdk.Folder.get_info(
|
|
966
|
-
user_id=user_id,
|
|
967
|
-
company_id=company_id,
|
|
968
|
-
scopeId="scope_w78wfn114va9o22s13r03yq",
|
|
969
|
-
)
|
|
970
|
-
```
|
|
971
|
-
|
|
972
|
-
By path:
|
|
973
|
-
|
|
974
|
-
```python
|
|
975
|
-
unique_sdk.Folder.get_info(
|
|
976
|
-
user_id=user_id,
|
|
977
|
-
company_id=company_id,
|
|
978
|
-
folderPath="/Company/Atlas/Due Dilligence/Arch,
|
|
979
|
-
)
|
|
980
|
-
```
|
|
981
|
-
|
|
982
|
-
#### `unique_sdl.Folder.get_infos`
|
|
983
|
-
|
|
984
|
-
Get paginated folders info based on parentId. If the parentId is not defined, the root folders will be returned.
|
|
985
|
-
|
|
986
|
-
```python
|
|
987
|
-
unique_sdk.Folder.get_infos(
|
|
988
|
-
user_id=user_id,
|
|
989
|
-
company_id=company_id,
|
|
990
|
-
take=10, #optional
|
|
991
|
-
skip=5, #optional
|
|
992
|
-
parentId="scope_s18seqpnltf35niydg77xgyp" #optional
|
|
993
|
-
)
|
|
994
|
-
```
|
|
995
|
-
|
|
996
|
-
#### `unique_sdk.Folder.create_paths`
|
|
997
|
-
|
|
998
|
-
Create each folder in the provided list of paths if it does not already exist.
|
|
999
|
-
|
|
1000
|
-
```python
|
|
1001
|
-
unique_sdk.Folder.create_paths(
|
|
1002
|
-
user_id=user_id,
|
|
1003
|
-
company_id=company_id,
|
|
1004
|
-
paths=["/unique/path1", "/unique/path2"],
|
|
1005
|
-
)
|
|
1006
|
-
```
|
|
1007
|
-
|
|
1008
|
-
#### `unique_sdk.Folder.update_ingestion_config`
|
|
1009
|
-
|
|
1010
|
-
Allows you to update the ingestion config of a folder and choose whether to apply to the subscopes or not: `
|
|
1011
|
-
|
|
1012
|
-
- `ingestionConfig`
|
|
1013
|
-
- `applyToSubScopes`
|
|
1014
|
-
|
|
1015
|
-
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.
|
|
1016
|
-
|
|
1017
|
-
Example of updating the ingestion config of a folder and its subfolders using the id.
|
|
1018
|
-
|
|
1019
|
-
```python
|
|
1020
|
-
unique_sdk.Folder.update_ingestion_config(
|
|
1021
|
-
user_id=user_id,
|
|
1022
|
-
company_id=company_id,
|
|
1023
|
-
scopeId="scope_qbnkde820dbmuw2900,
|
|
1024
|
-
ingestionConfig={
|
|
1025
|
-
"chunkStrategy": "default",
|
|
1026
|
-
"uniqueIngestionMode": "standard",
|
|
1027
|
-
},
|
|
1028
|
-
applyToSubScopes=True
|
|
1029
|
-
)
|
|
1030
|
-
```
|
|
1031
|
-
|
|
1032
|
-
Example of updating the ingestion config of a folder and its subfolders using the path.
|
|
1033
|
-
|
|
1034
|
-
```python
|
|
1035
|
-
unique_sdk.Folder.update_ingestion_config(
|
|
1036
|
-
user_id=user_id,
|
|
1037
|
-
company_id=company_id,
|
|
1038
|
-
folderPath="/Company/folder1/folder2",
|
|
1039
|
-
ingestionConfig={
|
|
1040
|
-
"chunkStrategy": "default",
|
|
1041
|
-
"uniqueIngestionMode": "standard",
|
|
1042
|
-
},
|
|
1043
|
-
applyToSubScopes=True
|
|
1044
|
-
)
|
|
1045
|
-
```
|
|
1046
|
-
|
|
1047
|
-
#### `unique_sdk.Folder.add_access`
|
|
1048
|
-
|
|
1049
|
-
Allows you to add access to a folder and apply to the subfolders or not: `
|
|
1050
|
-
|
|
1051
|
-
- `scopeAccesses`
|
|
1052
|
-
- `applyToSubScopes`
|
|
1053
|
-
|
|
1054
|
-
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.
|
|
1055
|
-
|
|
1056
|
-
Example of adding access to a folder and its subfolders using the id.
|
|
1057
|
-
|
|
1058
|
-
```python
|
|
1059
|
-
unique_sdk.Folder.add_access(
|
|
1060
|
-
user_id=user_id,
|
|
1061
|
-
company_id=company_id,
|
|
1062
|
-
scopeId="scope_231e4kjn4foffww34",
|
|
1063
|
-
scopeAccesses=[
|
|
1064
|
-
{
|
|
1065
|
-
"entityId": "group_id",
|
|
1066
|
-
"type": "WRITE",
|
|
1067
|
-
"entityType": "GROUP",
|
|
1068
|
-
}
|
|
1069
|
-
],
|
|
1070
|
-
applyToSubScopes=True,
|
|
1071
|
-
)
|
|
1072
|
-
```
|
|
1073
|
-
|
|
1074
|
-
Example of adding access to a folder and its subfolders using the folder path.
|
|
1075
|
-
|
|
1076
|
-
```python
|
|
1077
|
-
unique_sdk.Folder.add_access(
|
|
1078
|
-
user_id=user_id,
|
|
1079
|
-
company_id=company_id,
|
|
1080
|
-
folderPath="/Company/folder1/folder2"
|
|
1081
|
-
scopeAccesses=[
|
|
1082
|
-
{
|
|
1083
|
-
"entityId": "group_id",
|
|
1084
|
-
"type": "WRITE",
|
|
1085
|
-
"entityType": "GROUP",
|
|
1086
|
-
}
|
|
1087
|
-
],
|
|
1088
|
-
applyToSubScopes=True,
|
|
1089
|
-
)
|
|
1090
|
-
```
|
|
1091
|
-
|
|
1092
|
-
#### `unique_sdk.Folder.remove_access`
|
|
1093
|
-
|
|
1094
|
-
Allows you to delete access from a folder and apply to the subfolders or not:
|
|
1095
|
-
|
|
1096
|
-
- `scopeAccesses`
|
|
1097
|
-
- `applyToSubScopes`
|
|
1098
|
-
|
|
1099
|
-
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.
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
Example of deleting the access from a folder and its subfolders using the id.
|
|
1103
|
-
|
|
1104
|
-
```python
|
|
1105
|
-
unique_sdk.Folder.remove_access(
|
|
1106
|
-
user_id=user_id,
|
|
1107
|
-
company_id=company_id,
|
|
1108
|
-
scopeId="scope_dwekjnf3330woioppm,
|
|
1109
|
-
scopeAccesses=[
|
|
1110
|
-
{
|
|
1111
|
-
"entityId": "group_id",
|
|
1112
|
-
"type": "WRITE",
|
|
1113
|
-
"entityType": "GROUP",
|
|
1114
|
-
}
|
|
1115
|
-
],
|
|
1116
|
-
applyToSubScopes=True,
|
|
1117
|
-
)
|
|
1118
|
-
```
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
Example of deleting the access from a folder and its subfolders using the path.
|
|
1122
|
-
|
|
1123
|
-
```python
|
|
1124
|
-
unique_sdk.Folder.remove_access(
|
|
1125
|
-
user_id=user_id,
|
|
1126
|
-
company_id=company_id,
|
|
1127
|
-
folderPath="/Company/folder1/folder2"
|
|
1128
|
-
scopeAccesses=[
|
|
1129
|
-
{
|
|
1130
|
-
"entityId": "group_id",
|
|
1131
|
-
"type": "WRITE",
|
|
1132
|
-
"entityType": "GROUP",
|
|
1133
|
-
}
|
|
1134
|
-
],
|
|
1135
|
-
applyToSubScopes=True,
|
|
1136
|
-
)
|
|
1137
|
-
```
|
|
1138
|
-
|
|
1139
|
-
#### `unique_sdk.Folder.delete` (Compatible with release >.36)
|
|
1140
|
-
|
|
1141
|
-
Given a `scopeId` or `folderPath`, the function deletes the folder. If the folder is not empty or if the user has no WRITE access, the delete will fail.
|
|
1142
|
-
|
|
1143
|
-
If `recursive` is set to true, the function also deletes its subfolders and its contents, behaving exactly like the `rm -rf`. In case a subfolder has no write access, that folder is considered as failed to delete and the function continues with the other subfolders. At the end, the function returns a list of `successFolders` and `failedFolders`.
|
|
1144
|
-
|
|
1145
|
-
Examples:
|
|
1146
|
-
Deleting recursively by scope id:
|
|
1147
|
-
|
|
1148
|
-
```python
|
|
1149
|
-
unique_sdk.Folder.delete(
|
|
1150
|
-
user_id=user_id,
|
|
1151
|
-
company_id=company_id,
|
|
1152
|
-
scopeId="scope_w78wfn114va9o22s13r03yq",
|
|
1153
|
-
recursive=True
|
|
1154
|
-
)
|
|
1155
|
-
```
|
|
1156
|
-
|
|
1157
|
-
Deleting by path (non-recursive):
|
|
1158
|
-
|
|
1159
|
-
```python
|
|
1160
|
-
unique_sdk.Folder.delete(
|
|
1161
|
-
user_id=user_id,
|
|
1162
|
-
company_id=company_id,
|
|
1163
|
-
folderPath="/Company/Atlas/Due Dilligence/Arch",
|
|
1164
|
-
)
|
|
1165
|
-
```
|
|
1166
|
-
|
|
1167
|
-
### Space
|
|
1168
|
-
|
|
1169
|
-
#### `unique_sdk.Space.delete_chat`
|
|
1170
|
-
|
|
1171
|
-
Delete a space chat by id. If the chat does not exist, the function will return an error.
|
|
1172
|
-
|
|
1173
|
-
```python
|
|
1174
|
-
unique_sdk.Space.delete_chat(
|
|
1175
|
-
user_id=user_id,
|
|
1176
|
-
company_id=company_id,
|
|
1177
|
-
chat_id="chat_dejfhe729br398",
|
|
1178
|
-
)
|
|
1179
|
-
```
|
|
1180
|
-
|
|
1181
|
-
## UniqueQL
|
|
1182
|
-
|
|
1183
|
-
[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.
|
|
1184
|
-
|
|
1185
|
-
### UniqueQL Query Structure
|
|
1186
|
-
|
|
1187
|
-
A UniqueQL query is composed of a path, an operator, and a value. The path specifies the metadata attribute to be filtered, the operator defines the type of comparison, and the value provides the criteria for the filter.
|
|
1188
|
-
|
|
1189
|
-
A metadata filter can be designed with UniqueQL's `UQLOperator` and `UQLCombinator` as follows:
|
|
1190
|
-
|
|
1191
|
-
```python
|
|
1192
|
-
metadata_filter = {
|
|
1193
|
-
"path": ['diet', '*'],
|
|
1194
|
-
"operator": UQLOperator.NESTED,
|
|
1195
|
-
"value": {
|
|
1196
|
-
UQLCombinator.OR : [
|
|
1197
|
-
{
|
|
1198
|
-
UQLCombinator.OR: [
|
|
1199
|
-
{
|
|
1200
|
-
"path": ['food'],
|
|
1201
|
-
"operator": UQLOperator.EQUALS,
|
|
1202
|
-
"value": "meat",
|
|
1203
|
-
},
|
|
1204
|
-
{
|
|
1205
|
-
"path": ['food'],
|
|
1206
|
-
"operator": UQLOperator.EQUALS,
|
|
1207
|
-
"value": 'vegis',
|
|
1208
|
-
},
|
|
1209
|
-
],
|
|
1210
|
-
},
|
|
1211
|
-
{
|
|
1212
|
-
"path": ['likes'],
|
|
1213
|
-
"operator": UQLOperator.EQUALS,
|
|
1214
|
-
"value": true,
|
|
1215
|
-
},
|
|
1216
|
-
],
|
|
1217
|
-
},
|
|
1218
|
-
}
|
|
1219
|
-
```
|
|
1220
|
-
|
|
1221
|
-
### Metadata Filtering
|
|
1222
|
-
|
|
1223
|
-
A metadata filter such as the one designed above can be used in a `Search.create` call by passing it the `metaDataFilter` parameter.
|
|
1224
|
-
|
|
1225
|
-
```python
|
|
1226
|
-
search_results = unique_sdk.Search.create(
|
|
1227
|
-
user_id=user_id,
|
|
1228
|
-
company_id=company_id,
|
|
1229
|
-
chatId=chat_id,
|
|
1230
|
-
searchString=search_string,
|
|
1231
|
-
searchType="COMBINED",
|
|
1232
|
-
# limit=2,
|
|
1233
|
-
metaDataFilter=metadata_filter,
|
|
1234
|
-
)
|
|
1235
|
-
```
|
|
1236
|
-
|
|
1237
|
-
## Utils
|
|
1238
|
-
|
|
1239
|
-
- [Chat History](#chat-history)
|
|
1240
|
-
- [File Io](#file-io)
|
|
1241
|
-
- [Sources](#sources)
|
|
1242
|
-
- [token](#token)
|
|
1243
|
-
- [Chat In Space](#chat-in-space)
|
|
1244
|
-
|
|
1245
|
-
### Chat History
|
|
1246
|
-
|
|
1247
|
-
#### `unique_sdk.utils.chat_history.load_history`
|
|
1248
|
-
|
|
1249
|
-
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.
|
|
1250
|
-
|
|
1251
|
-
- `maxTokens` max tokens of the model used
|
|
1252
|
-
- `percentOfMaxTokens`=0.15 % max history in % of `maxTokens`
|
|
1253
|
-
- `maxMessages`=4, maximal number of messages included in the history.
|
|
1254
|
-
|
|
1255
|
-
this method also directly returns a correct formatted history that can be used in the next chat round.
|
|
1256
|
-
|
|
1257
|
-
```python
|
|
1258
|
-
history = unique_sdk.utils.chat_history.load_history(
|
|
1259
|
-
userId,
|
|
1260
|
-
companyId,
|
|
1261
|
-
chatId
|
|
1262
|
-
)
|
|
1263
|
-
```
|
|
1264
|
-
|
|
1265
|
-
#### `unique_sdk.utils.chat_history.convert_chat_history_to_injectable_string`
|
|
1266
|
-
|
|
1267
|
-
convert history into a string that can be injected into a prompt. it als returns the token length of the converted history.
|
|
1268
|
-
|
|
1269
|
-
```
|
|
1270
|
-
chat_history-string, chat_context_token_length = unique_sdk.utils.chat_history.convert_chat_history_to_injectable_string(
|
|
1271
|
-
history
|
|
1272
|
-
)
|
|
1273
|
-
```
|
|
1274
|
-
|
|
1275
|
-
### File Io
|
|
1276
|
-
|
|
1277
|
-
Interacting with the knowledge-base.
|
|
1278
|
-
|
|
1279
|
-
#### `unique_sdk.utils.file_io.download_content`
|
|
1280
|
-
|
|
1281
|
-
download files and save them into a folder in `/tmp`
|
|
1282
|
-
|
|
1283
|
-
for example using the readUrl from a content.
|
|
1284
|
-
|
|
1285
|
-
```python
|
|
1286
|
-
pdfFile = download_content(
|
|
1287
|
-
companyId=companyId,
|
|
1288
|
-
userId=userId,
|
|
1289
|
-
content_id="cont_12412",
|
|
1290
|
-
filename="hello.pdf",
|
|
1291
|
-
chat_id=None # If specified, it downloads it from the chat
|
|
1292
|
-
)
|
|
1293
|
-
```
|
|
1294
|
-
|
|
1295
|
-
#### `unique_sdk.utils.file_io.upload_file`
|
|
1296
|
-
|
|
1297
|
-
Allows for uploading files that then get ingested in a scope or a chat.
|
|
1298
|
-
|
|
1299
|
-
```python
|
|
1300
|
-
createdContent = upload_file(
|
|
1301
|
-
companyId=companyId,
|
|
1302
|
-
userId=userId,
|
|
1303
|
-
path_to_file="/tmp/hello.pdf",
|
|
1304
|
-
displayed_filename="hello.pdf",
|
|
1305
|
-
mime_type="application/pdf",
|
|
1306
|
-
scope_or_unique_path="scope_stcj2osgbl722m22jayidx0n",
|
|
1307
|
-
chat_id=None,
|
|
1308
|
-
)
|
|
1309
|
-
```
|
|
1310
|
-
|
|
1311
|
-
### Sources
|
|
1312
|
-
|
|
1313
|
-
#### `unique_sdk.utils.sources.merge_sources`
|
|
1314
|
-
|
|
1315
|
-
Merges multiple search results based on their 'id', removing redundant document and info markers.
|
|
1316
|
-
|
|
1317
|
-
This function groups search results by their 'id' and then concatenates their texts,
|
|
1318
|
-
cleaning up any document or info markers in subsequent chunks beyond the first one.
|
|
1319
|
-
|
|
1320
|
-
Parameters:
|
|
1321
|
-
|
|
1322
|
-
- searchContext (list): A list of dictionaries, each representing a search result with 'id' and 'text' keys.
|
|
1323
|
-
|
|
1324
|
-
Returns:
|
|
1325
|
-
|
|
1326
|
-
- list: A list of dictionaries with merged texts for each unique 'id'.
|
|
1327
|
-
|
|
1328
|
-
`searchContext` is an list of search objects that are returned by the search.
|
|
1329
|
-
|
|
1330
|
-
```python
|
|
1331
|
-
search = unique_sdk.Search.create(
|
|
1332
|
-
user_id=userId,
|
|
1333
|
-
company_id=companyId,
|
|
1334
|
-
chatId=chatId,
|
|
1335
|
-
searchString="Who is Harry P?",
|
|
1336
|
-
searchType="COMBINED",
|
|
1337
|
-
scopeIds="scope_dsf...",
|
|
1338
|
-
limit=30,
|
|
1339
|
-
chatOnly=False,
|
|
1340
|
-
)
|
|
1341
|
-
|
|
1342
|
-
searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
|
|
1343
|
-
search["data"], config["maxTokens"] - historyLength
|
|
1344
|
-
)
|
|
1345
|
-
|
|
1346
|
-
searchContext = unique_sdk.utils.sources.merge_sources(search)
|
|
1347
|
-
|
|
1348
|
-
```
|
|
1349
|
-
|
|
1350
|
-
#### `unique_sdk.utils.sources.sort_sources`
|
|
1351
|
-
|
|
1352
|
-
Sort sources by order of appearance in documents
|
|
1353
|
-
|
|
1354
|
-
```python
|
|
1355
|
-
|
|
1356
|
-
search = unique_sdk.Search.create(
|
|
1357
|
-
user_id=userId,
|
|
1358
|
-
company_id=companyId,
|
|
1359
|
-
chatId=chatId,
|
|
1360
|
-
searchString="Who is Harry P?",
|
|
1361
|
-
searchType="COMBINED",
|
|
1362
|
-
scopeIds="scope_dsf...",
|
|
1363
|
-
limit=30,
|
|
1364
|
-
chatOnly=False,
|
|
1365
|
-
)
|
|
1366
|
-
|
|
1367
|
-
searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
|
|
1368
|
-
search["data"], config["maxTokens"] - historyLength
|
|
1369
|
-
)
|
|
1370
|
-
|
|
1371
|
-
searchContext = unique_sdk.utils.sources.sort_sources(search)
|
|
1372
|
-
```
|
|
1373
|
-
|
|
1374
|
-
#### `unique_sdk.utils.sources.post_process_sources`
|
|
1375
|
-
|
|
1376
|
-
Post-processes the provided text by converting source references into superscript numerals (required
|
|
1377
|
-
format by backend to display sources in the chat window)
|
|
1378
|
-
|
|
1379
|
-
This function searches the input text for patterns that represent source references (e.g., [source1])
|
|
1380
|
-
and replaces them with superscript tags, incrementing the number by one.
|
|
1381
|
-
|
|
1382
|
-
Parameters:
|
|
1383
|
-
|
|
1384
|
-
- text (str): The text to be post-processed.
|
|
1385
|
-
|
|
1386
|
-
Returns:
|
|
1387
|
-
|
|
1388
|
-
- str: The text with source references replaced by superscript numerals.
|
|
1389
|
-
|
|
1390
|
-
Examples:
|
|
1391
|
-
|
|
1392
|
-
- postprocessSources("This is a reference [source0]") will return "This is a reference <sup>1</sup>".
|
|
1393
|
-
|
|
1394
|
-
```python
|
|
1395
|
-
|
|
1396
|
-
text_with_sup = post_process_sources(text)
|
|
1397
|
-
```
|
|
1398
|
-
|
|
1399
|
-
### Token
|
|
1400
|
-
|
|
1401
|
-
#### unique_sdk.utils.token.pick_search_results_for_token_window
|
|
1402
|
-
|
|
1403
|
-
Selects and returns a list of search results that fit within a specified token limit.
|
|
1404
|
-
|
|
1405
|
-
This function iterates over a list of search results, each with a 'text' field, and
|
|
1406
|
-
encodes the text using a predefined encoding scheme. It accumulates search results
|
|
1407
|
-
until the token limit is reached or exceeded.
|
|
1408
|
-
|
|
1409
|
-
Parameters:
|
|
1410
|
-
|
|
1411
|
-
- searchResults (list): A list of dictionaries, each containing a 'text' key with string value.
|
|
1412
|
-
- tokenLimit (int): The maximum number of tokens to include in the output.
|
|
1413
|
-
|
|
1414
|
-
Returns:
|
|
1415
|
-
|
|
1416
|
-
- list: A list of dictionaries representing the search results that fit within the token limit.
|
|
1417
|
-
|
|
1418
|
-
```python
|
|
1419
|
-
search = unique_sdk.Search.create(
|
|
1420
|
-
user_id=userId,
|
|
1421
|
-
company_id=companyId,
|
|
1422
|
-
chatId=chatId,
|
|
1423
|
-
searchString="Who is Harry P?",
|
|
1424
|
-
searchType="COMBINED",
|
|
1425
|
-
scopeIds="scope_dsf...",
|
|
1426
|
-
limit=30,
|
|
1427
|
-
chatOnly=False,
|
|
1428
|
-
)
|
|
1429
|
-
|
|
1430
|
-
searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
|
|
1431
|
-
search["data"], config["maxTokens"] - historyLength
|
|
1432
|
-
)
|
|
1433
|
-
```
|
|
1434
|
-
|
|
1435
|
-
#### unique_sdk.utils.token.count_tokens
|
|
1436
|
-
|
|
1437
|
-
Counts the number of tokens in the provided text.
|
|
1438
|
-
|
|
1439
|
-
This function encodes the input text using a predefined encoding scheme
|
|
1440
|
-
and returns the number of tokens in the encoded text.
|
|
1441
|
-
|
|
1442
|
-
Parameters:
|
|
1443
|
-
|
|
1444
|
-
- text (str): The text to count tokens for.
|
|
1445
|
-
|
|
1446
|
-
Returns:
|
|
1447
|
-
|
|
1448
|
-
- int: The number of tokens in the text.
|
|
1449
|
-
|
|
1450
|
-
```python
|
|
1451
|
-
hello = "hello you!"
|
|
1452
|
-
searchContext = unique_sdk.utils.token.count_tokens(hello)
|
|
1453
|
-
```
|
|
1454
|
-
|
|
1455
|
-
### Chat In Space
|
|
1456
|
-
|
|
1457
|
-
#### `unique_sdk.utils.chat_in_space.send_message_and_wait_for_completion`
|
|
1458
|
-
|
|
1459
|
-
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.
|
|
1460
|
-
|
|
1461
|
-
The script sends a prompt asynchronously and continuously polls for completion, which is determined when the `stoppedStreamingAt` field of the message becomes non-null.
|
|
1462
|
-
|
|
1463
|
-
**Optional parameters:**
|
|
1464
|
-
- `tool_choices`: A list of tool names to be used for the message (e.g., `["WebSearch"]`). If not provided, no tools will be used. The tools supported right now are `WebSearch` and `InternalSearch`.
|
|
1465
|
-
- `scope_rules`: A filter to specify the scope rules for the message, allowing you to restrict the context or data sources available to the assistant. The filter is written in UniqueQL language. Find out more about the language in the UniqueQL section.
|
|
1466
|
-
- `chat_id`: The ID of the chat where the message should be sent. If omitted, a new chat will be created.
|
|
1467
|
-
- `poll_interval`: The number of seconds to wait between polling attempts (default: `1` second).
|
|
1468
|
-
- `max_wait`: The maximum number of seconds to wait for the message to complete (default: `60` seconds).
|
|
1469
|
-
- `stop_condition`: Defines when to expect a response back, when the assistant stop streaming or when it completes the message. (default: "stoppedStreamingAt")
|
|
1470
|
-
|
|
1471
|
-
The script ensures you can flexibly interact with spaces in new or ongoing chats, with fine-grained control over tools, context, and polling behavior.
|
|
1472
|
-
|
|
1473
|
-
```python
|
|
1474
|
-
from unique_sdk.utils.chat_in_space import send_message_and_wait_for_completion
|
|
1475
|
-
latest_message = await send_message_and_wait_for_completion(
|
|
1476
|
-
user_id=user_id,
|
|
1477
|
-
company_id=company_id,
|
|
1478
|
-
assistant_id=assistant_id,
|
|
1479
|
-
text="Tell me a short story.",
|
|
1480
|
-
chat_id=chat_id, # Optional - if no chat id is specified, a new chat will be created
|
|
1481
|
-
tool_choices=["WebSearch"],
|
|
1482
|
-
scope_rules={
|
|
1483
|
-
"or": [
|
|
1484
|
-
{
|
|
1485
|
-
"operator": "in",
|
|
1486
|
-
"path": [
|
|
1487
|
-
"contentId"
|
|
1488
|
-
],
|
|
1489
|
-
"value": [
|
|
1490
|
-
"cont_u888z7cazxxm4lugfdjq7pks"
|
|
1491
|
-
]
|
|
1492
|
-
},
|
|
1493
|
-
{
|
|
1494
|
-
"operator": "contains",
|
|
1495
|
-
"path": [
|
|
1496
|
-
"folderIdPath"
|
|
1497
|
-
],
|
|
1498
|
-
"value": "uniquepathid://scope_btfo28b3eeelwh5obwgea71bl/scope_fn56ta67knd6w4medgq3028fx"
|
|
1499
|
-
}
|
|
1500
|
-
]
|
|
1501
|
-
},
|
|
1502
|
-
stop_condition = "completedAt" # If not specified, stoppedStreamingAt will be set by default
|
|
1503
|
-
)
|
|
1504
|
-
```
|
|
1505
|
-
|
|
1506
|
-
#### `unique_sdk.utils.chat_in_space.chat_against_file`
|
|
1507
|
-
|
|
1508
|
-
The following script enables you to chat against a file.
|
|
1509
|
-
|
|
1510
|
-
You must provide the following parameters:
|
|
1511
|
-
- `assistantId`: The assistant to be used for the chat.
|
|
1512
|
-
- `path_to_file`: The local path of the file to be uploaded.
|
|
1513
|
-
- `displayed_filename`: The name of the file to be displayed.
|
|
1514
|
-
- `mime_type`: The mime type of the ifle to be uploaded.
|
|
1515
|
-
- `text`: The text to be sent to the chat for chatting against the file.
|
|
1516
|
-
|
|
1517
|
-
The script creates a chat and uploads the file to it. It then keeps polling the `ingestionState` field of the message, waiting for it to reach `FINISHED`, signaling the upload is complete. Once the file uploads successfully, the script sends the text, continues polling for completion, and finally retrieves the response message.
|
|
1518
|
-
|
|
1519
|
-
**Optional parameters:**
|
|
1520
|
-
- `poll_interval`: The number of seconds to wait between polling attempts (default: `1` second).
|
|
1521
|
-
- `max_wait`: The maximum number of seconds to wait for the message to complete (default: `60` seconds).
|
|
1522
|
-
|
|
1523
|
-
Example of chatting against a PDF. (The usage can be extended to any supported file type)
|
|
1524
|
-
|
|
1525
|
-
```python
|
|
1526
|
-
latest_message = await unique_sdk.utils.chat_in_space.chat_against_file(
|
|
1527
|
-
user_id=user_id,
|
|
1528
|
-
company_id=company_id,
|
|
1529
|
-
assistant_id="assistant_hjcdga64bkcjnhu4",
|
|
1530
|
-
path_to_file="/files/hello.pdf",
|
|
1531
|
-
displayed_filename="hello.pdf"
|
|
1532
|
-
mime_type="application/pdf"
|
|
1533
|
-
text="Give me a bullet point summary of the file.",
|
|
1534
|
-
)
|
|
1535
|
-
```
|
|
1536
|
-
|
|
1537
|
-
#### `unique_sdk.utils.chat_in_space.wait_for_ingestion_completion`
|
|
1538
|
-
|
|
1539
|
-
The following script enables you to wait for the ingestion of a file. This should be used carefully as it continuously polls for the status. In case of bigger files, adjust the `poll_interval` and `max_waits`.
|
|
1540
|
-
|
|
1541
|
-
You must provide the following parameter:
|
|
1542
|
-
- `content_id`: The id of the content to check.
|
|
1543
|
-
|
|
1544
|
-
The script polls until the content ingestion is finished or the maximum wait time is reached and throws in case ingestion fails. The function assumes that the content exists.
|
|
1545
|
-
|
|
1546
|
-
**Optional parameters:**
|
|
1547
|
-
- `chat_id`: In case the content is uploaded to a chat, the `chat_id` must be provided.
|
|
1548
|
-
- `poll_interval`: The number of seconds to wait between polling attempts (default: `1` second).
|
|
1549
|
-
- `max_wait`: The maximum number of seconds to wait for the message to complete (default: `60` seconds).
|
|
1550
|
-
|
|
1551
|
-
Example of waiting for the ingestion of a file in the Knowledge Base.
|
|
1552
|
-
|
|
1553
|
-
```python
|
|
1554
|
-
await unique_sdk.utils.chat_in_space.wait_for_ingestion_completion(
|
|
1555
|
-
user_id=user_id,
|
|
1556
|
-
company_id=company_id,
|
|
1557
|
-
content_id="cont_ddlezvag4kzxudfr24lrjc5mx",
|
|
1558
|
-
)
|
|
1559
|
-
```
|
|
1560
|
-
|
|
1561
|
-
## Error Handling
|
|
1562
|
-
|
|
1563
|
-
## Examples
|
|
1564
|
-
|
|
1565
|
-
An example Flask app demonstrating the usage of each API resource and how to interact with Webhooks is available in our repository at `/examples/custom-assistant`.
|
|
1566
|
-
|
|
1567
|
-
## Credits
|
|
1568
|
-
|
|
1569
|
-
This is a _fork_ / inspired-by the fantastic Stripe Python SDK (https://github.com/stripe/stripe-python).
|
|
1570
|
-
|
|
1571
|
-
# Changelog
|
|
1572
|
-
|
|
1573
|
-
All notable changes to this project will be documented in this file.
|
|
1574
|
-
|
|
1575
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
1576
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
1577
|
-
|
|
1578
|
-
## [0.10.19] - 2025-09-02
|
|
1579
|
-
- Improve `send_message_and_wait_for_completion`:
|
|
1580
|
-
- Add option to select stop_condition `["stoppedStreamingAt", "completedAt"]`.
|
|
1581
|
-
- Load `debugInfo` from `last_user_message` for better developer experience.
|
|
1582
|
-
|
|
1583
|
-
## [0.10.18] - 2025-09-02
|
|
1584
|
-
- Temporarily remove support for update and delete files by filePath.
|
|
1585
|
-
|
|
1586
|
-
## [0.10.17] - 2025-09-01
|
|
1587
|
-
- Add function to update a file
|
|
1588
|
-
|
|
1589
|
-
## [0.10.16] - 2025-08-31
|
|
1590
|
-
- Add function to delete a content.
|
|
1591
|
-
|
|
1592
|
-
## [0.10.15] - 2025-08-28
|
|
1593
|
-
- Add default values for message log types
|
|
1594
|
-
|
|
1595
|
-
## [0.10.14] - 2025-08-28
|
|
1596
|
-
- Add function to delete folders and files recursively
|
|
1597
|
-
|
|
1598
|
-
## [0.10.13] - 2025-08-24
|
|
1599
|
-
- Add functions to create, get and update a message eecution and create and update a message log.
|
|
1600
|
-
|
|
1601
|
-
## [0.10.12] - 2025-08-24
|
|
1602
|
-
- Switch to using Content get info deprecated endpoint to make sure we support older release versions.
|
|
1603
|
-
|
|
1604
|
-
## [0.10.11] - 2025-08-24
|
|
1605
|
-
- Enforce usage of ruff using pipeline
|
|
1606
|
-
|
|
1607
|
-
## [0.10.10] - 2025-08-18
|
|
1608
|
-
- Fix wrong name of references in `Space.Message`.
|
|
1609
|
-
- Fix wrong name of assessment in `Space.Message`.
|
|
1610
|
-
- Remove default values for `text`, `originalText` and `debugInfo` in `Space.Message` as these don't have an effect.
|
|
1611
|
-
|
|
1612
|
-
## [0.10.9] - 2025-08-15
|
|
1613
|
-
- Add script to wait for content ingestion finished.
|
|
1614
|
-
|
|
1615
|
-
## [0.10.8] - 2025-08-13
|
|
1616
|
-
- Add support for Agentic Table.
|
|
1617
|
-
|
|
1618
|
-
## [0.10.7] - 2025-08-13
|
|
1619
|
-
- Make metadata optional when uploading a file.
|
|
1620
|
-
|
|
1621
|
-
## [0.10.6] - 2025-08-06
|
|
1622
|
-
- Make tools optional for running an agent.
|
|
1623
|
-
|
|
1624
|
-
## [0.10.5] - 2025-08-06
|
|
1625
|
-
- Get paginated files and folders info.
|
|
1626
|
-
|
|
1627
|
-
## [0.10.4] - 2025-08-05
|
|
1628
|
-
- Add support for reasoning API with streaming within a chat.
|
|
1629
|
-
|
|
1630
|
-
## [0.10.3] - 2025-08-05
|
|
1631
|
-
- Expose scoreThreshold param for search.
|
|
1632
|
-
|
|
1633
|
-
## [0.10.2] - 2025-08-05
|
|
1634
|
-
- Add script to chat against file.
|
|
1635
|
-
|
|
1636
|
-
## [0.10.1] - 2025-08-05
|
|
1637
|
-
- Allow deletion of a space chat.
|
|
1638
|
-
|
|
1639
|
-
## [0.10.0] - 2025-08-04
|
|
1640
|
-
- Add MCP support
|
|
1641
|
-
|
|
1642
|
-
## [0.9.42] - 2025-07-31
|
|
1643
|
-
- Fix wrong chat in space example.
|
|
1644
|
-
|
|
1645
|
-
## [0.9.41] - 2025-07-31
|
|
1646
|
-
- Fix double-slash error in open ai proxy script.
|
|
1647
|
-
|
|
1648
|
-
## [0.9.40] - 2025-07-22
|
|
1649
|
-
- Fixed bug where get requests send body with the request. This is not allowed by WAF policies.
|
|
1650
|
-
|
|
1651
|
-
## [0.9.39] - 2025-07-18
|
|
1652
|
-
- Add script to chat in a space.
|
|
1653
|
-
|
|
1654
|
-
## [0.9.38] - 2025-07-18
|
|
1655
|
-
- [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`.
|
|
1656
|
-
|
|
1657
|
-
## [0.9.37] - 2025-07-10
|
|
1658
|
-
- Add `sheetName` property to the `MagicTableSheetIngestParams` object used by function that ingests magic table sheets.
|
|
1659
|
-
|
|
1660
|
-
## [0.9.36] - 2025-06-23
|
|
1661
|
-
- Allow passing a user id when creating chat completions. This is optional and it does not impact the current behaviour.
|
|
1662
|
-
|
|
1663
|
-
## [0.9.35] - 2025-06-18
|
|
1664
|
-
- Allow scope access updates (add/remove) on folder based on scope id or path.
|
|
1665
|
-
|
|
1666
|
-
## [0.9.34] - 2025-06-17
|
|
1667
|
-
- Allow ingestion config updates on folder based on scope id or path.
|
|
1668
|
-
|
|
1669
|
-
## [0.9.33] - 2025-06-11
|
|
1670
|
-
- Add function to get a folder by id or by path.
|
|
1671
|
-
|
|
1672
|
-
## [0.9.32] - 2025-06-11
|
|
1673
|
-
- Add function to ingest magic table sheets.
|
|
1674
|
-
|
|
1675
|
-
## [0.9.31] - 2025-05-21
|
|
1676
|
-
- Add function to update folder access (add or remove).
|
|
1677
|
-
|
|
1678
|
-
## [0.9.30] - 2025-05-21
|
|
1679
|
-
- Add function to update folder ingestion config.
|
|
1680
|
-
|
|
1681
|
-
## [0.9.29] - 2025-05-20
|
|
1682
|
-
- Add function to create folder paths if they do not exist.
|
|
1683
|
-
|
|
1684
|
-
## [0.9.28] - 2025-05-20
|
|
1685
|
-
- Add function to search content info. This also allows filtering content info by metadata info.
|
|
1686
|
-
|
|
1687
|
-
## [0.9.27] - 2025-05-14
|
|
1688
|
-
- Add the possibility to specify metadata when creating or updating a Content.
|
|
1689
|
-
|
|
1690
|
-
## [0.9.26] - 2025-05-13
|
|
1691
|
-
- Add the possibility to specify ingestionConfig when creating or updating a Content.
|
|
1692
|
-
|
|
1693
|
-
## [0.9.25] - 2025-05-02
|
|
1694
|
-
- Fixed typos in `README.md`, including incorrect `sdk.utils` imports and code example errors.
|
|
1695
|
-
|
|
1696
|
-
## [0.9.24] - 2025-04-23
|
|
1697
|
-
- Make `chatId` property in `Search.CreateParams` optional
|
|
1698
|
-
|
|
1699
|
-
## [0.9.23] - 2025-03-25
|
|
1700
|
-
- Define programming language classifier explicitly for python 3.11
|
|
1701
|
-
|
|
1702
|
-
## [0.9.22] - 2025-02-25
|
|
1703
|
-
- update the retry_on_error to only `APIError` and `APIConnectionError` update the `resp["error"]` to be `resp.get("error")` to avoid key error
|
|
1704
|
-
|
|
1705
|
-
## [0.9.21] - 2025-02-21
|
|
1706
|
-
- Add title parameter and change labels in `MessageAssessment`
|
|
1707
|
-
|
|
1708
|
-
## [0.9.20] - 2025-02-01
|
|
1709
|
-
- Add url parameter to `MessageAssessment.create_async` and `MessageAssessment.modify_async`
|
|
1710
|
-
|
|
1711
|
-
## [0.9.19] - 2025-01-31
|
|
1712
|
-
- Add `MessageAssessment` resource
|
|
1713
|
-
|
|
1714
|
-
## [0.9.18] - 2025-01-22
|
|
1715
|
-
- Removed `Invalid response body from API` from `retry_dict` as it's our own artificail error.
|
|
1716
|
-
|
|
1717
|
-
## [0.9.17] - 2025-01-03
|
|
1718
|
-
- BREAKING CHANGE!! Removed unused `id` from `ShortTermMemory` create and find methods.
|
|
1719
|
-
|
|
1720
|
-
## [0.9.16] - 2024-12-19
|
|
1721
|
-
- Corrected return type of `Search.create` and `Search.create_async` to `List[Search]`
|
|
1722
|
-
- Retry on `Connection aborted` error
|
|
1723
|
-
|
|
1724
|
-
## [0.9.15] - 2024-12-06
|
|
1725
|
-
- Add `Internal server error` and `You can retry your request` to the retry logic
|
|
1726
|
-
|
|
1727
|
-
## [0.9.14] - 2024-12-06
|
|
1728
|
-
- Add `contentIds` to `Search.create` and `Search.create_async`
|
|
1729
|
-
|
|
1730
|
-
## [0.9.13] - 2024-10-23
|
|
1731
|
-
- Add retry for `5xx` errors, add additional error message.
|
|
1732
|
-
|
|
1733
|
-
## [0.9.12] - 2024-11-21
|
|
1734
|
-
- Include original error message in returned exceptions
|
|
1735
|
-
|
|
1736
|
-
## [0.9.11] - 2024-11-18
|
|
1737
|
-
- Add `ingestionConfig` to `UpsertParams.Input` parameters
|
|
1738
|
-
|
|
1739
|
-
## [0.9.10] - 2024-10-23
|
|
1740
|
-
- Remove `temperature` parameter from `Integrated.chat_stream_completion`, `Integrated.chat_stream_completion_async`, `ChatCompletion.create` and `ChatCompletion.create_async` methods. To use `temperature` parameter, set the attribute in `options` parameter instead.
|
|
1741
|
-
|
|
1742
|
-
## [0.9.9] - 2024-10-23
|
|
1743
|
-
- Revert deletion of `Message.retrieve` method
|
|
1744
|
-
|
|
1745
|
-
## [0.9.8] - 2024-10-16
|
|
1746
|
-
- Add `retries` for `_static_request` and `_static_request_async` in `APIResource` - When the error messages contains either `"problem proxying the request"`,
|
|
1747
|
-
or `"Upstream service reached a hard timeout"`,
|
|
1748
|
-
## [0.9.7] - 2024-09-23
|
|
1749
|
-
- Add `completedAt` to `CreateParams` of `Message`
|
|
1750
|
-
|
|
1751
|
-
## [0.9.6] - 2024-09-03
|
|
1752
|
-
- Added `metaDataFilter` to `Search` parameters.
|
|
1753
|
-
|
|
1754
|
-
## [0.9.5] - 2024-08-07
|
|
1755
|
-
- Add `completedAt` to `ModifyParams`
|
|
1756
|
-
|
|
1757
|
-
## [0.9.4] - 2024-07-31
|
|
1758
|
-
- Add `close` and `close_async` to `http_client`
|
|
1759
|
-
- Make `httpx` the default client for async requests
|
|
1760
|
-
|
|
1761
|
-
## [0.9.3] - 2024-07-31
|
|
1762
|
-
- `Search.create`, `Message`, `ChatCompletion` parameters that were marked `NotRequired` are now also `Optional`
|
|
1763
|
-
|
|
1764
|
-
## [0.9.2] - 2024-07-30
|
|
1765
|
-
- Bug fix in `Search.create`: langugage -> language
|
|
1766
|
-
|
|
1767
|
-
## [0.9.1] - 2024-07-30
|
|
1768
|
-
- Added parameters to `Search.create` and `Search.create_async`
|
|
1769
|
-
- `language` for full text search
|
|
1770
|
-
- `reranker` to reranker search results
|
|
1771
|
-
|
|
1772
|
-
## [0.9.0] - 2024-07-29
|
|
1773
|
-
- Added the possibility to make async requests to the unique APIs using either aiohttp or httpx as client
|
|
1774
|
-
|