unique_sdk 0.10.47__py3-none-any.whl → 0.10.53__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.
@@ -1,2431 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: unique_sdk
3
- Version: 0.10.47
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
- Provides-Extra: openai
14
- Requires-Dist: openai (>=1.105.0,<2.0.0) ; extra == "openai"
15
- Requires-Dist: requests (>=2.32.3,<3.0.0)
16
- Requires-Dist: typing-extensions (>=4.9.0,<5.0.0)
17
- Description-Content-Type: text/markdown
18
-
19
- # Unique Python SDK
20
-
21
- Unique AI is a tailored solution for the financial industry, designed to increase productivity by automating manual workloads through AI and ChatGPT solutions.
22
-
23
- The Unique Python SDK provides access to the public API of Unique AI. It also enables verification of Webhook signatures to ensure the authenticity of incoming Webhook requests.
24
-
25
- ## Table of Contents
26
-
27
- 1. [Installation](#installation)
28
- 2. [Requirements](#requirements)
29
- 3. [Usage Instructions](#usage-instructions)
30
- 4. [Webhook Triggers](#webhook-triggers)
31
- 5. [Available API Resources](#available-api-resources)
32
- - [Content](#content)
33
- - [Message](#message)
34
- - [Message Log](#message-log)
35
- - [Message Execution](#message-execution)
36
- - [Chat Completion](#chat-completion)
37
- - [Embeddings](#embeddings)
38
- - [Acronyms](#acronyms)
39
- - [Search](#search)
40
- - [Search String](#search-string)
41
- - [Short Term Memory](#short-term-memory)
42
- - [Message Assessment](#message-assessment)
43
- - [Folder](#folder)
44
- - [Space](#space)
45
- - [LLM Models](#llm-models)
46
- - [User](#user)
47
- - [Group](#group)
48
- - [Agentic Table](#agentic-table)
49
- 6. [UniqueQL](#uniqueql)
50
- - [Query Structure](#uniqueql-query-structure)
51
- - [Metadata Filtering](#metadata-filtering)
52
- 7. [Util functions](#utils)
53
- - [Chat History](#chat-history)
54
- - [File Io](#file-io)
55
- - [Sources](#sources)
56
- - [token](#token)
57
- - [Chat In Space](#chat-in-space)
58
- 8. [Error Handling](#error-handling)
59
- 9. [Examples](#examples)
60
-
61
- ## Installation
62
-
63
- Install UniqueSDK and its peer dependency `requests` and when planning to run async requests also `httpx` or `aiohttp` via pip using the following commands:
64
-
65
- ```bash
66
- pip install unique_sdk
67
- pip install requests
68
- ```
69
-
70
- Optional for async requests:
71
-
72
- ```bash
73
- pip install httpx
74
- ```
75
-
76
- or
77
-
78
- ```bash
79
- pip install aiohttp
80
- ```
81
-
82
- ## Requirements
83
-
84
- - Python >=3.11 (Other Python versions 3.6+ might work but are not tested)
85
- - requests (peer dependency. Other HTTP request libraries might be supported in the future)
86
- - Unique App-ID & API Key
87
-
88
- Please contact your customer success manager at Unique for your personal developer App-ID & API Key.
89
-
90
- ## Usage instructions
91
-
92
- 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`.
93
-
94
- ```python
95
- import unique_sdk
96
- unique_sdk.api_key = "ukey_..."
97
- unique_sdk.app_id = "app_..."
98
- ```
99
-
100
- The SDK includes a set of classes for API resources. Each class contains CRUD methods to interact with the resource.
101
-
102
- ### Example
103
-
104
- ```python
105
- import unique_sdk
106
- unique_sdk.api_key = "ukey_..."
107
- unique_sdk.app_id = "app_..."
108
-
109
- # list messages for a single chat
110
- messages = unique_sdk.Message.list(
111
- user_id=user_id,
112
- company_id=company_id,
113
- chatId=chat_id,
114
- )
115
-
116
- print(messages.data[0].text)
117
- ```
118
-
119
- ## Webhook Triggers
120
-
121
- A core functionality of Unique AI is the ability for users to engage in an interactive chat feature. SDK developers can hook into this chat to provide new functionalities.
122
-
123
- Your App (refer to `app-id` in [Requirements](#requirements)) must be subscribed to each individual Unique event in order to receive a webhook.
124
-
125
- Each webhook sent by Unique includes a set of headers:
126
-
127
- ```yaml
128
- X-Unique-Id: evt_... # Event id, same as in the body.
129
- X-Unique-Signature: ... # A HMAC-SHA256 hex signature of the entire body.
130
- X-Unique-Version: 1.0.0 # Event payload version.
131
- X-Unique-Created-At: 1705960141 # Unix timestamp (seconds) of the delivery time.
132
- X-Unique-User-Id: ... # The user who initiated the message.
133
- X-Unique-Company-Id: ... # The company to which the user belongs.
134
- ```
135
-
136
- ### Success & Retry on Failure
137
-
138
- - Webhooks are considered successfully delivered if your endpoint returns a status code between `200` and `299`.
139
- - 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.
140
- - If your endpoint returns any other status (e.g., `404`), it is marked as expired and will not receive any further requests.
141
-
142
- ### Webhook Signature Verification
143
-
144
- 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:
145
-
146
- ```python
147
- from http import HTTPStatus
148
- from flask import Flask, jsonify, request
149
- import unique_sdk
150
-
151
- endpoint_secret = "YOUR_ENDPOINT_SECRET"
152
-
153
- @app.route("/webhook", methods=["POST"])
154
- def webhook():
155
- event = None
156
- payload = request.data
157
-
158
- sig_header = request.headers.get("X-Unique-Signature")
159
- timestamp = request.headers.get("X-Unique-Created-At")
160
-
161
- if not sig_header or not timestamp:
162
- print("⚠️ Webhook signature or timestamp headers missing.")
163
- return jsonify(success=False), HTTPStatus.BAD_REQUEST
164
-
165
- try:
166
- event = unique_sdk.Webhook.construct_event(
167
- payload, sig_header, timestamp, endpoint_secret
168
- )
169
- except unique_sdk.SignatureVerificationError as e:
170
- print("⚠️ Webhook signature verification failed. " + str(e))
171
- return jsonify(success=False), HTTPStatus.BAD_REQUEST
172
- ```
173
-
174
- 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.:
175
-
176
- ```python
177
- event = unique_sdk.Webhook.construct_event(
178
- payload, sig_header, timestamp, endpoint_secret, 0
179
- )
180
- ```
181
-
182
- ### Available Unique Events
183
-
184
- #### User Message Created
185
-
186
- ```json
187
- {
188
- "id": "evt_...", // see header
189
- "version": "1.0.0", // see header
190
- "event": "unique.chat.user-message.created", // The name of the event
191
- "createdAt": "1705960141", // see header
192
- "userId": "...", // see header
193
- "companyId": "...", // see header
194
- "payload": {
195
- "chatId": "chat_...", // The id of the chat
196
- "assistantId": "assistant_...", // The id of the selected assistant
197
- "text": "Hello, how can I help you?" // The user message
198
- }
199
- }
200
- ```
201
-
202
- 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.
203
-
204
- 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.
205
-
206
- #### External Module Chosen
207
-
208
- ```json
209
- {
210
- "id": "evt_...",
211
- "version": "1.0.0",
212
- "event": "unique.chat.external-module.chosen",
213
- "createdAt": "1705960141", // Unix timestamp (seconds)
214
- "userId": "...",
215
- "companyId": "...",
216
- "payload": {
217
- "name": "example-sdk", // The name of the module selected by the module chooser
218
- "description": "Example SDK", // The description of the module
219
- "configuration": {}, // Module configuration in JSON format
220
- "chatid": "chat_...", // The chat ID
221
- "assistantId:": "assistant_...", // The assistant ID
222
- "userMessage": {
223
- "id": "msg_...",
224
- "text": "Hello World!", // The user message leading to the module selection
225
- "createdAt": "2024-01-01T00:00:00.000Z" // ISO 8601
226
- },
227
- "assistantMessage": {
228
- "id": "msg_...",
229
- "createdAt": "2024-01-01T00:00:00.000Z" // ISO 8601
230
- }
231
- }
232
- }
233
- ```
234
-
235
- This Webhook is triggered when the Unique 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.
236
-
237
- Unique's UI will create an empty `assistantMessage` below the user message and update this message with status updates.
238
-
239
- **The SDK is expected to modify this assistantMessage with its answer to the user message.**
240
-
241
- ```python
242
- unique_sdk.Message.modify(
243
- user_id=user_id,
244
- company_id=company_id,
245
- id=assistant_message_id,
246
- chatId=chat_id,
247
- text="Here is your answer.",
248
- )
249
- ```
250
-
251
- ## Available API Resources
252
-
253
- - [Content](#content)
254
- - [Message](#message)
255
- - [Message Log](#message-log)
256
- - [Message Execution](#message-execution)
257
- - [Chat Completion](#chat-completion)
258
- - [Embeddings](#embeddings)
259
- - [Acronyms](#acronyms)
260
- - [Search](#search)
261
- - [Search String](#search-string)
262
- - [Short Term Memory](#short-term-memory)
263
- - [Message Assessment](#message-assessment)
264
- - [Folder](#folder)
265
- - [Space](#space)
266
- - [LLM Models](#llm-models)
267
- - [User](#user)
268
- - [Group](#group)
269
- - [Agentic Table](#agentic-table)
270
-
271
- Most of the API services provide an asynchronous version of the method. The async methods are suffixed with `_async`.
272
-
273
- ### Content
274
-
275
- #### `unique_sdk.Content.search`
276
-
277
- 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: `
278
-
279
- - `id`
280
- - `key`
281
- - `ownerId`
282
- - `title`
283
- - `url`
284
-
285
- 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.
286
-
287
- ```python
288
- unique_sdk.Content.search(
289
- user_id=userId,
290
- company_id=companyId,
291
- where={
292
- "OR": [
293
- {
294
- "title": {
295
- "contains": "42",
296
- },
297
- },
298
- {
299
- "key": {
300
- "contains": "42",
301
- },
302
- },
303
- ],
304
- },
305
- chatId=chatId,
306
- )
307
- ```
308
-
309
- #### `unique_sdk.Content.get_info`
310
-
311
- [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:
312
-
313
- ```python
314
- metadataFilter: {
315
- "or": [
316
- {
317
- "and": [
318
- {
319
- "operator": "contains",
320
- "path": [
321
- "folderIdPath"
322
- ],
323
- "value": "uniquepathid://test_id"
324
- },
325
- {
326
- "operator": "contains",
327
- "path": [
328
- "title"
329
- ],
330
- "value": "ai"
331
- }
332
- ]
333
- }
334
- ]
335
- },
336
- ```
337
-
338
- 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:`
339
-
340
- - `skip`
341
- - `take`
342
-
343
- 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.
344
-
345
- ```python
346
- content_info_result = unique_sdk.Content.get_info(
347
- user_id=user_id,
348
- company_id=company_id,
349
- metadataFilter={
350
- "or": [
351
- {
352
- "and": [
353
- {
354
- "operator": "contains",
355
- "path": [
356
- "folderIdPath"
357
- ],
358
- "value": "uniquepathid://scope_abcdibgznc4bkdcx120zm5d"
359
- },
360
- {
361
- "operator": "contains",
362
- "path": [
363
- "title"
364
- ],
365
- "value": "ai"
366
- }
367
- ]
368
- }
369
- ]
370
- },
371
- skip=0,
372
- take=3,
373
- )
374
- ```
375
-
376
- #### `unique_sdk.Content.get_infos`
377
-
378
- 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.
379
-
380
- 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:
381
-
382
- ```python
383
- metadataFilter: {
384
- "or": [
385
- {
386
- "and": [
387
- {
388
- "operator": "contains",
389
- "path": [
390
- "folderIdPath"
391
- ],
392
- "value": "uniquepathid://test_id"
393
- },
394
- {
395
- "operator": "contains",
396
- "path": [
397
- "title"
398
- ],
399
- "value": "ai"
400
- }
401
- ]
402
- }
403
- ]
404
- },
405
- ```
406
-
407
- 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:`
408
-
409
- - `skip`
410
- - `take`
411
-
412
- 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.
413
-
414
- ```python
415
- content_info_result = unique_sdk.Content.get_infos(
416
- user_id=user_id,
417
- company_id=company_id,
418
- metadataFilter={
419
- "or": [
420
- {
421
- "and": [
422
- {
423
- "operator": "contains",
424
- "path": [
425
- "folderIdPath"
426
- ],
427
- "value": "uniquepathid://scope_abcdibgznc4bkdcx120zm5d"
428
- },
429
- {
430
- "operator": "contains",
431
- "path": [
432
- "title"
433
- ],
434
- "value": "ai"
435
- }
436
- ]
437
- }
438
- ]
439
- },
440
- skip=0,
441
- take=3,
442
- )
443
- ```
444
-
445
- Here is an example of retrieving the contents based on a parentId.
446
-
447
- ```python
448
- content_info_result = unique_sdk.Content.get_infos(
449
- user_id=user_id,
450
- company_id=company_id,
451
- parentId="scope_ahefgj389srjbfejkkk98u"
452
- )
453
- ```
454
-
455
- #### `unique_sdk.Content.upsert`
456
-
457
- 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.
458
-
459
- Typical usage is the following. That creates a Content and uploads a file
460
-
461
- ```python
462
-
463
- createdContent = upload_file(
464
- userId,
465
- companyId,
466
- "/path/to/file.pdf",
467
- "test.pdf",
468
- "application/pdf",
469
- "scope_stcj2osgbl722m22jayidx0n",
470
- ingestionConfig={
471
- "chunkMaxTokens": 1000,
472
- "chunkStrategy": "default",
473
- "uniqueIngestionMode": "standard",
474
- },
475
- metadata={
476
- "folderIdPath": "uniquepathid://scope_id"
477
- }
478
- )
479
-
480
- def upload_file(
481
- userId,
482
- companyId,
483
- path_to_file,
484
- displayed_filename,
485
- mimeType,
486
- description=None,
487
- scope_or_unique_path,
488
- ingestion_config=None,
489
- metadata=None,
490
- ):
491
- size = os.path.getsize(path_to_file)
492
- createdContent = unique_sdk.Content.upsert(
493
- user_id=userId,
494
- company_id=companyId,
495
- input={
496
- "key": displayed_filename,
497
- "title": displayed_filename,
498
- "mimeType": mimeType,
499
- "description": description,
500
- "ingestionConfig": ingestionConfig,
501
- "metadata": metadata,
502
- },
503
- scopeId=scope_or_unique_path,
504
- )
505
-
506
- uploadUrl = createdContent.writeUrl
507
-
508
- # upload to azure blob storage SAS url uploadUrl the pdf file translatedFile make sure it is treated as a application/pdf
509
- with open(path_to_file, "rb") as file:
510
- requests.put(
511
- uploadUrl,
512
- data=file,
513
- headers={
514
- "X-Ms-Blob-Content-Type": mimeType,
515
- "X-Ms-Blob-Type": "BlockBlob",
516
- },
517
- )
518
-
519
- unique_sdk.Content.upsert(
520
- user_id=userId,
521
- company_id=companyId,
522
- input={
523
- "key": displayed_filename,
524
- "title": displayed_filename,
525
- "mimeType": mimeType,
526
- "description": description,
527
- "byteSize": size,
528
- "ingestionConfig": ingestionConfig,
529
- "metadata": metadata,
530
- },
531
- scopeId=scope_or_unique_path,
532
- readUrl=createdContent.readUrl,
533
- )
534
-
535
- return createdContent
536
-
537
- ```
538
-
539
- #### `unique_sdk.Content.ingest_magic_table_sheets`
540
-
541
- Allows you to ingest a magic table sheet, each row is processed and converted into a content.
542
- ```python
543
- params = {
544
- "user_id": user_id,
545
- "company_id": company_id,
546
- "data": [
547
- {
548
- "rowId": "2",
549
- "columns": [
550
- {"columnId": "0", "columnName": "Section", "content": "Other"},
551
- {"columnId": "1", "columnName": "Question", "content": "What do you know?"},
552
- {
553
- "columnId": "2",
554
- "columnName": "Knowledge Base Answer",
555
- "content": "Lorem Ipsum is simply dummy texktop publishing software.",
556
- },
557
- ],
558
- },
559
- ],
560
- "ingestionConfiguration": {
561
- "columnIdsInMetadata": ["1", "2"],
562
- "columnIdsInChunkText": ["1", "2"],
563
- },
564
- "metadata": {
565
- "libraryName": "foo",
566
- },
567
- "scopeId": scope_id,
568
- "sheetName": "Sheet1",
569
- }
570
-
571
- unique_sdk.Content.ingest_magic_table_sheets(**params)
572
- ```
573
-
574
- #### `unique_sdk.Content.update` (Compatible with release >.36)
575
-
576
- Allows you to update a file specified by its `contentId` or by its `filePath`.
577
-
578
- - `contentId` optional if `filePath` is provided, the id of the file to be updated
579
- - `filePath` optional if `contentId` is provided, the absolute path of the file to be updated
580
-
581
- Currently, the following updates are supported:
582
-
583
- Title update:
584
- - `title` optional, allows updating the title of the file
585
-
586
- Move the file to a different folder. This can be done by specifying either the `ownerId` or the `parentFolderPath`.
587
- - `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`.
588
- - `parentFolderPath` optional, allows moving the file to a different folder. Represents the path new folder for the file.
589
-
590
- Metadata update:
591
- - `metadata` optional, allows updating the metadata of the file. Default metadata can not be overridden. (Available with release >.40)
592
-
593
- Example of updating the title of a file specified by its path.
594
-
595
- ```python
596
- unique_sdk.Content.update(
597
- user_id=user_id,
598
- company_id=company_id,
599
- filePath="/Company/finance/january.xls",
600
- title="Revision Deck"
601
- )
602
- ```
603
-
604
- Example of moving a file specified by its content id.
605
-
606
- ```python
607
- unique_sdk.Content.update(
608
- user_id=user_id,
609
- company_id=company_id,
610
- contentId="cont_ok2343q5owbce80w78hudawu5",
611
- ownerId="scope_e68yz5asho7glfh7c7d041el",
612
- metadata={
613
- "quarter": "q1",
614
- }
615
- )
616
- ```
617
-
618
- Example of moving a file and updating its title.
619
-
620
- ```python
621
- unique_sdk.Content.update(
622
- user_id=user_id,
623
- company_id=company_id,
624
- contentId="cont_ok2343q5owbce80w78hudawu5",
625
- ownerId="scope_e68yz5asho7glfh7c7d041el",
626
- title="Revision Deck (1)"
627
- )
628
- ```
629
-
630
- Example of moving a file to a folder specified by its path.
631
-
632
- ```python
633
- unique_sdk.Content.update(
634
- user_id=user_id,
635
- company_id=company_id,
636
- contentId="cont_ok2343q5owbce80w78hudawu5",
637
- ownerId="scope_e68yz5asho7glfh7c7d041el",
638
- parentFolderPath="/Company/Revisions"
639
- )
640
- ```
641
-
642
- #### `unique_sdk.Content.delete` (Compatible with release >.36)
643
-
644
- Allows you to delete a file by its `contentId`. If the file is part of a chat, the `chatId` also needs do be set.
645
-
646
- - `contentId` optional if `filePath` is provided, the id of the file to be deleted
647
- - `chatId` optional, the id of the chat where the file is. Only needed if the file is part of a chat
648
- - `filePath` optional if `contentId` is provided, the absolute path of the file to be deleted
649
-
650
- Example of deleting a file from a chat.
651
-
652
- ```python
653
- unique_sdk.Content.delete(
654
- user_id=user_id,
655
- company_id=company_id,
656
- contentId="cont_ok2343q5owbce80w78hudawu5",
657
- chatId="chat_v3xfa7liv876h89vuiibus1"
658
- )
659
- ```
660
-
661
- Example of deleting a file by its path.
662
-
663
- ```python
664
- unique_sdk.Content.delete(
665
- user_id=user_id,
666
- company_id=company_id,
667
- filePath="/Company/finance/january.xls",
668
- )
669
- ```
670
-
671
-
672
- ### Message
673
-
674
- #### `unique_sdk.Message.list`
675
-
676
- Retrieve a list of messages for a provided `chatId`.
677
-
678
- ```python
679
- messages = unique_sdk.Message.list(
680
- user_id=user_id,
681
- company_id=company_id,
682
- chatId=chat_id,
683
- )
684
- ```
685
-
686
- #### `unique_sdk.Message.retrieve`
687
-
688
- Get a single chat message.
689
-
690
- ```python
691
- message = unique_sdk.Message.retrieve(
692
- user_id=user_id,
693
- company_id=company_id,
694
- id=message_id,
695
- chatId=chat_id,
696
- )
697
- ```
698
-
699
- #### `unique_sdk.Message.create`
700
-
701
- Create a new message in a chat.
702
-
703
- ```python
704
- message = unique_sdk.Message.create(
705
- user_id=user_id,
706
- company_id=company_id,
707
- chatId=chat_id,
708
- assistantId=assistant_id,
709
- text="Hello.",
710
- role="ASSISTANT",
711
- )
712
- ```
713
-
714
- #### `unique_sdk.Message.create_event`
715
-
716
- Create a new message event in a chat. Updating the text of a message in the chat UI is possible by creating a message update event. This function can be used for custom streaming to the chat. (Compatible with release >.42)
717
-
718
- The event only changes the text in the UI, it *does not* update the database.
719
-
720
- ```python
721
- message = unique_sdk.Message.create_event(
722
- user_id=user_id,
723
- company_id=company_id,
724
- messageId="msg_l4ushn85yqbewpf6tllh2cl7",
725
- chatId="chat_kc8p3kgkn7393qhgmv5js5nt",
726
- text="Hello.", #optional
727
- originalText="Hello.", #optional
728
- references=[], #optional
729
- gptRequest={} #optional
730
- debugInfo={ "hello": "test" }, #optional
731
- )
732
- ```
733
-
734
- #### `unique_sdk.Message.modify`
735
-
736
- Modify an existing chat message.
737
-
738
- ℹ️ if you modify the debugInfo only do it on the user message as this is the only place that is displayed in the frontend.
739
-
740
- ```python
741
- message = unique_sdk.Message.modify(
742
- user_id=user_id,
743
- company_id=company_id,
744
- id=message_id,
745
- chatId=chat_id,
746
- text="Updated message text"
747
- )
748
- ```
749
-
750
- #### `unique_sdk.Message.delete`
751
-
752
- Delete a chat message.
753
-
754
- ```python
755
- message = unique_sdk.Message.delete(
756
- message_id,
757
- user_id=user_id,
758
- company_id=company_id,
759
- chatId=chat_id,
760
- )
761
- ```
762
-
763
- #### `unique_sdk.Integrated.stream`
764
-
765
- Streams the answer to the chat frontend. Given the messages.
766
-
767
- if the stream creates [source0] it is referenced with the references from the search context.
768
-
769
- E.g.
770
-
771
- ```
772
- Hello this information is from [srouce1]
773
- ```
774
-
775
- adds the reference at index 1 and then changes the text to:
776
-
777
- ```
778
- Hello this information is from <sub>0</sub>
779
- ```
780
-
781
- ```python
782
- unique_sdk.Integrated.chat_stream_completion(
783
- user_id=userId,
784
- company_id=companyId,
785
- assistantMessageId=assistantMessageId,
786
- userMessageId=userMessageId,
787
- messages=[
788
- {
789
- "role": "system",
790
- "content": "be friendly and helpful"
791
- },
792
- {
793
- "role": "user",
794
- "content": "hello"
795
- }
796
- ],
797
- chatId=chatId,
798
-
799
- searchContext= [
800
- {
801
- "id": "ref_qavsg0dcl5cbfwm1fvgogrvo",
802
- "chunkId": "0",
803
- "key": "some reference.pdf : 8,9,10,11",
804
- "sequenceNumber": 1,
805
- "url": "unique://content/cont_p8n339trfsf99oc9f36rn4wf"
806
- }
807
- ], # optional
808
- debugInfo={
809
- "hello": "test"
810
- }, # optional
811
- startText= "I want to tell you about: ", # optional
812
- model= "AZURE_GPT_4_32K_0613", # optional
813
- timeout=8000, # optional in ms
814
- options={
815
- "temperature": 0.5
816
- } # optional
817
- )
818
- ```
819
-
820
- **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.
821
-
822
-
823
- #### `unique_sdk.Integrated.responses_stream`
824
-
825
- Streams the answer to the chat frontend using the Responses API. Given the messages.
826
-
827
- if the stream creates [source0] it is referenced with the references from the search context.
828
-
829
- E.g.
830
-
831
- ```
832
- Hello this information is from [source1]
833
- ```
834
-
835
- adds the reference at index 1 and then changes the text to:
836
-
837
- ```
838
- Hello this information is from <sub>0</sub>
839
- ```
840
-
841
- ```python
842
- unique_sdk.Integrated.responses_stream(
843
- user_id=userId,
844
- company_id=companyId,
845
- model="AZURE_o3_2025_0416",
846
- assistantMessageId=assistantMessageId,
847
- userMessageId=userMessageId,
848
- input="Tell me about the curious case of neural text degeneration",
849
- chatId=chatId,
850
- )
851
- ```
852
-
853
- **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.
854
-
855
- ### Message Log
856
-
857
- #### `unique_sdk.MessageLog.create`
858
-
859
- Function to update the steps section of a message in the chat UI. This is possible by creating a message log record during a message execution.
860
-
861
- ```python
862
- msg_log = unique_sdk.MessageLog.create(
863
- user_id=user_id,
864
- company_id=company_id,
865
- messageId="msg_a0jgnt1jrqv1d3uzr450waxw",
866
- text="Create message log text",
867
- order=1,
868
- status="RUNNING", # one of "RUNNING", "COMPLETED", "FAILED"
869
- details={}, # optional, details dictionary
870
- uncitedReferences={}, # optional, references dictionary
871
- references=[], # optional, list of references
872
- )
873
- ```
874
-
875
- #### `unique_sdk.MessageLog.update`
876
-
877
- Update a message log for a provided `messageId`.
878
-
879
- ```python
880
- msg_log = unique_sdk.MessageLog.update(
881
- user_id=user_id,
882
- company_id=company_id,
883
- message_log_id="message_log_fd7z7gjljo1z2wu5g6l9q7r9",
884
- text="Update a message log text", # optional
885
- order=1, # optional
886
- status="RUNNING", # one of "RUNNING", "COMPLETED", "FAILED"
887
- details={}, # optional, details dictionary
888
- uncitedReferences={}, # optional, references dictionary
889
- references=[], # optional, list of references
890
- )
891
- ```
892
-
893
- ### Message Execution
894
-
895
- #### `unique_sdk.MessageExecution.create`
896
-
897
- Create a message execution for a provided `messageId` and `chatId`.
898
-
899
- ```python
900
- msg_execution = unique_sdk.MessageExecution.create(
901
- user_id=user_id,
902
- company_id=company_id,
903
- messageId="msg_a0jgnt1jrqv143uzr750waxw",
904
- type="DEEP_RESEARCH",
905
- )
906
- ```
907
-
908
- #### `unique_sdk.MessageExecution.get`
909
-
910
- Get a message execution for a provided `messageId`.
911
-
912
- ```python
913
- msg_execution = unique_sdk.MessageExecution.get(
914
- user_id=user_id,
915
- company_id=company_id,
916
- messageId="msg_a0jgnt1jrqv143uzr750waxw",
917
- )
918
- ```
919
-
920
- #### `unique_sdk.MessageExecution.update`
921
-
922
- Update a message execution for a provided `messageId`.
923
-
924
- ```python
925
- msg_execution = unique_sdk.MessageExecution.update(
926
- user_id=user_id,
927
- company_id=company_id,
928
- messageId="msg_a0jgnt1jrqv143uzr750waxw",
929
- status="COMPLETED", # optional, one of: COMPLETED, FAILED - not specifying the status will have no effect over the status
930
- secondsRemaining=55, # optional, number defining the seconds remaining
931
- percentageCompleted=10, # optional, number defining the percentage completed
932
- )
933
- ```
934
-
935
- ### Chat Completion
936
-
937
- #### `unique_sdk.ChatCompletion.create`
938
-
939
- Send a prompt to an AI model supported by Unique AI and receive a result. The `messages` attribute must follow the [OpenAI API format](https://platform.openai.com/docs/api-reference/chat).
940
-
941
- ```python
942
- chat_completion = unique_sdk.ChatCompletion.create(
943
- company_id=company_id,
944
- user_id=user_id
945
- model="AZURE_GPT_4o_2024_1120",
946
- messages=[
947
- {"role": "system", "content": "You are a helpful assistant."},
948
- {"role": "user", "content": "Hello!"},
949
- ],
950
- options={
951
- "temperature": 0.5, # optional
952
- } # optional
953
- )
954
- ```
955
-
956
- ### Embeddings
957
-
958
- #### `unique_sdk.Embeddings.create`
959
-
960
- Sends an array of `text` to the AI model for embedding. And retrieve a vector of embeddings.
961
-
962
- ```python
963
- result = unique_sdk.Embeddings.create(
964
- user_id=user_id,
965
- company_id=company_id,
966
- texts=["hello", "hello"],
967
- )
968
- print(result.embeddings[0][0])
969
- ```
970
-
971
- ### Acronyms
972
-
973
- #### `unique_sdk.Acronyms.get`
974
-
975
- 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.
976
-
977
- ```python
978
- result = unique_sdk.Acronyms.get(
979
- user_id=user_id,
980
- company_id=company_id,
981
- )
982
- print(result)
983
- ```
984
-
985
- ### Search
986
-
987
- #### `unique_sdk.Search.create`
988
-
989
- Search the Unique AI 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.
990
-
991
- These are the options are available for `searchType`:
992
-
993
- - `VECTOR`
994
- - `COMBINED`
995
-
996
- `limit` (max 1000) and `page` are optional for iterating over results.
997
- `chatOnly` Restricts the search exclusively to documents uploaded within the chat.
998
- `scopeIds` Specifies a collection of scope IDs to confine the search.
999
- `language` Optional. The language specification for full text search.
1000
- `reranker` Optional. The reranker service to be used for re-ranking the search results.
1001
- `chatId` Optional, adds the documents uploaded in this chat to the scope of searched documents.
1002
- `scoreThreshold` Optional, sets the minimum similarity score for search results to be considered. Using 0 is recommended.
1003
-
1004
- ```python
1005
- search = unique_sdk.Search.create(
1006
- user_id=user_id,
1007
- company_id=company_id,
1008
- chatId=chat_id
1009
- searchString="What is the meaning of life, the universe and everything?",
1010
- searchType="VECTOR",
1011
- chatOnly=false,
1012
- scopeIds=["scope_..."],
1013
- language="German",
1014
- reranker={"deploymentName": "my_deployment"},
1015
- limit=20,
1016
- page=1
1017
- scoreThreshold=0
1018
- )
1019
- ```
1020
-
1021
- ### Search String
1022
-
1023
- #### `unique_sdk.SearchString.create`
1024
-
1025
- 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.
1026
-
1027
- 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.
1028
-
1029
- 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.
1030
-
1031
- ```python
1032
- search_string = unique_sdk.SearchString.create(
1033
- user_id=user_id,
1034
- company_id=company_id,
1035
- prompt="Was ist der Sinn des Lebens, des Universums und des ganzen Rests?",
1036
- chat_id=chat_id
1037
- )
1038
- ```
1039
-
1040
- ### Short Term Memory
1041
-
1042
- 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.
1043
- For this 10k chars can be used. You can save a short term memory for a chat `chatId` or for a message `messageId`.
1044
- you need to provide an `memoryName` as an identifier.
1045
-
1046
- you can then save it and retreive it live defined below.
1047
-
1048
-
1049
- #### `unique_sdk.ShortTermMemory.create`
1050
-
1051
- ```python
1052
- c = unique_sdk.ShortTermMemory.create(
1053
- user_id=user_id,
1054
- company_id=company_id,
1055
- data="hello",
1056
- chatId="chat_x0xxtj89f7drjp4vmued3q",
1057
- # messageId = "msg_id",
1058
- memoryName="your memory name",
1059
- )
1060
- print(c)
1061
- ```
1062
-
1063
- #### `unique_sdk.ShortTermMemory.find-latest`
1064
-
1065
- ```python
1066
- m = unique_sdk.ShortTermMemory.find_latest(
1067
- user_id=user_id,
1068
- company_id=company_id,
1069
- chatId="chat_x0xxtj89f7drjp4vmued3q",
1070
- # messageId = "msg_id",
1071
- memoryName="your memory name",
1072
- )
1073
- print(m)
1074
- ```
1075
-
1076
- ### Message Assessment
1077
-
1078
- Used to create and modify message assessments for tracking hallucinations and compliance evaluations of assistant messages.
1079
-
1080
- #### `unique_sdk.MessageAssessment.create`
1081
-
1082
- Create a new message assessment for an assistant message.
1083
-
1084
- ```python
1085
- assessment = unique_sdk.MessageAssessment.create(
1086
- user_id=user_id,
1087
- company_id=company_id,
1088
- assistant_message_id="msg_...",
1089
- status="DONE",
1090
- explanation="This response contains incorrect information about...",
1091
- label="RED",
1092
- type="HALLUCINATION",
1093
- title="Hallucination detected",
1094
- isVisible=True
1095
- )
1096
- ```
1097
-
1098
- #### `unique_sdk.MessageAssessment.modify`
1099
-
1100
- Modify an existing message assessment.
1101
-
1102
- ```python
1103
- assessment = unique_sdk.MessageAssessment.modify(
1104
- user_id=user_id,
1105
- company_id=company_id,
1106
- assistant_message_id="msg_...",
1107
- status="DONE",
1108
- explanation="Updated explanation...",
1109
- label="RED",
1110
- title="update title"
1111
- type="HALLUCINATION"
1112
- )
1113
- ```
1114
-
1115
- ### Folder
1116
-
1117
- #### `unique_sdk.Folder.get_info`
1118
-
1119
- Get a folder by scope id or by path.
1120
-
1121
- By scope id:
1122
-
1123
- ```python
1124
- unique_sdk.Folder.get_info(
1125
- user_id=user_id,
1126
- company_id=company_id,
1127
- scopeId="scope_w78wfn114va9o22s13r03yq",
1128
- )
1129
- ```
1130
-
1131
- By path:
1132
-
1133
- ```python
1134
- unique_sdk.Folder.get_info(
1135
- user_id=user_id,
1136
- company_id=company_id,
1137
- folderPath="/Company/Atlas/Due Dilligence/Arch,
1138
- )
1139
- ```
1140
-
1141
- #### `unique_sdl.Folder.get_infos`
1142
-
1143
- Get paginated folders info based on parentId. If the parentId is not defined, the root folders will be returned.
1144
-
1145
- ```python
1146
- unique_sdk.Folder.get_infos(
1147
- user_id=user_id,
1148
- company_id=company_id,
1149
- take=10, #optional
1150
- skip=5, #optional
1151
- parentId="scope_s18seqpnltf35niydg77xgyp" #optional
1152
- )
1153
- ```
1154
-
1155
- #### `unique_sdk.Folder.create_paths`
1156
-
1157
- Create each folder in the provided list of paths if it does not already exist.
1158
-
1159
- ```python
1160
- unique_sdk.Folder.create_paths(
1161
- user_id=user_id,
1162
- company_id=company_id,
1163
- paths=["/unique/path1", "/unique/path2"],
1164
- )
1165
- ```
1166
-
1167
- #### `unique_sdk.Folder.update_ingestion_config`
1168
-
1169
- Allows you to update the ingestion config of a folder and choose whether to apply to the subscopes or not: `
1170
-
1171
- - `ingestionConfig`
1172
- - `applyToSubScopes`
1173
-
1174
- 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.
1175
-
1176
- Example of updating the ingestion config of a folder and its subfolders using the id.
1177
-
1178
- ```python
1179
- unique_sdk.Folder.update_ingestion_config(
1180
- user_id=user_id,
1181
- company_id=company_id,
1182
- scopeId="scope_qbnkde820dbmuw2900,
1183
- ingestionConfig={
1184
- "chunkStrategy": "default",
1185
- "uniqueIngestionMode": "standard",
1186
- },
1187
- applyToSubScopes=True
1188
- )
1189
- ```
1190
-
1191
- Example of updating the ingestion config of a folder and its subfolders using the path.
1192
-
1193
- ```python
1194
- unique_sdk.Folder.update_ingestion_config(
1195
- user_id=user_id,
1196
- company_id=company_id,
1197
- folderPath="/Company/folder1/folder2",
1198
- ingestionConfig={
1199
- "chunkStrategy": "default",
1200
- "uniqueIngestionMode": "standard",
1201
- },
1202
- applyToSubScopes=True
1203
- )
1204
- ```
1205
-
1206
- #### `unique_sdk.Folder.add_access`
1207
-
1208
- Allows you to add access to a folder and apply to the subfolders or not: `
1209
-
1210
- - `scopeAccesses`
1211
- - `applyToSubScopes`
1212
-
1213
- 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.
1214
-
1215
- Example of adding access to a folder and its subfolders using the id.
1216
-
1217
- ```python
1218
- unique_sdk.Folder.add_access(
1219
- user_id=user_id,
1220
- company_id=company_id,
1221
- scopeId="scope_231e4kjn4foffww34",
1222
- scopeAccesses=[
1223
- {
1224
- "entityId": "group_id",
1225
- "type": "WRITE",
1226
- "entityType": "GROUP",
1227
- }
1228
- ],
1229
- applyToSubScopes=True,
1230
- )
1231
- ```
1232
-
1233
- Example of adding access to a folder and its subfolders using the folder path.
1234
-
1235
- ```python
1236
- unique_sdk.Folder.add_access(
1237
- user_id=user_id,
1238
- company_id=company_id,
1239
- folderPath="/Company/folder1/folder2"
1240
- scopeAccesses=[
1241
- {
1242
- "entityId": "group_id",
1243
- "type": "WRITE",
1244
- "entityType": "GROUP",
1245
- }
1246
- ],
1247
- applyToSubScopes=True,
1248
- )
1249
- ```
1250
-
1251
- #### `unique_sdk.Folder.remove_access`
1252
-
1253
- Allows you to delete access from a folder and apply to the subfolders or not:
1254
-
1255
- - `scopeAccesses`
1256
- - `applyToSubScopes`
1257
-
1258
- 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.
1259
-
1260
-
1261
- Example of deleting the access from a folder and its subfolders using the id.
1262
-
1263
- ```python
1264
- unique_sdk.Folder.remove_access(
1265
- user_id=user_id,
1266
- company_id=company_id,
1267
- scopeId="scope_dwekjnf3330woioppm,
1268
- scopeAccesses=[
1269
- {
1270
- "entityId": "group_id",
1271
- "type": "WRITE",
1272
- "entityType": "GROUP",
1273
- }
1274
- ],
1275
- applyToSubScopes=True,
1276
- )
1277
- ```
1278
-
1279
-
1280
- Example of deleting the access from a folder and its subfolders using the path.
1281
-
1282
- ```python
1283
- unique_sdk.Folder.remove_access(
1284
- user_id=user_id,
1285
- company_id=company_id,
1286
- folderPath="/Company/folder1/folder2"
1287
- scopeAccesses=[
1288
- {
1289
- "entityId": "group_id",
1290
- "type": "WRITE",
1291
- "entityType": "GROUP",
1292
- }
1293
- ],
1294
- applyToSubScopes=True,
1295
- )
1296
- ```
1297
-
1298
- #### `unique_sdk.Folder.update`
1299
- Uupdate a folder specified by its `scopeId` or path. The following properties can be updated:
1300
- - parent folder - move the folder to a new parent folder specified by its `scopeId` or path. If the new parent folder is the root folder, the `parentId` should be explicitly specificed by setting `newParentId` to `None`.
1301
- - name - update the name by setting the `name` field to the new name.
1302
-
1303
- Examples:
1304
-
1305
- Move the folder specified by its `scopeId` to a new parent folder specified by its path.
1306
-
1307
- ```python
1308
- unique_sdk.Folder.update(
1309
- user_id=user_id,
1310
- company_id=company_id,
1311
- scopeId="scope_dwekjnf3330woioppm",
1312
- parentFolderPath="/Company/folder1/folder2"
1313
- )
1314
- ```
1315
-
1316
- Move the parent of a folder specified by its path to a new parent folder specified by its `scopeId` and update the name to "January".
1317
-
1318
- ```python
1319
- unique_sdk.Folder.update(
1320
- user_id=user_id,
1321
- company_id=company_id,
1322
- folderPath="/Company/folder1",
1323
- parentId="scope_dweekjrfhirtuhgroppm",
1324
- name="January"
1325
- )
1326
- ```
1327
-
1328
- Move the parent of a folder specified by its path to the root folder and update the name to "January".
1329
-
1330
- ```python
1331
- unique_sdk.Folder.update(
1332
- user_id=user_id,
1333
- company_id=company_id,
1334
- folderPath="/Company/folder1",
1335
- parentId=None,
1336
- name="January"
1337
- )
1338
- ```
1339
-
1340
-
1341
- #### `unique_sdk.Folder.delete` (Compatible with release >.36)
1342
-
1343
- 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.
1344
-
1345
- 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`.
1346
-
1347
- Examples:
1348
- Deleting recursively by scope id:
1349
-
1350
- ```python
1351
- unique_sdk.Folder.delete(
1352
- user_id=user_id,
1353
- company_id=company_id,
1354
- scopeId="scope_w78wfn114va9o22s13r03yq",
1355
- recursive=True
1356
- )
1357
- ```
1358
-
1359
- Deleting by path (non-recursive):
1360
-
1361
- ```python
1362
- unique_sdk.Folder.delete(
1363
- user_id=user_id,
1364
- company_id=company_id,
1365
- folderPath="/Company/Atlas/Due Dilligence/Arch",
1366
- )
1367
- ```
1368
-
1369
- ### Space
1370
-
1371
- #### `unique_sdk.Space.create_message`
1372
-
1373
- Send a message in a space. You can optionally provide a chat ID to continue an existing conversation, or omit it to start a new chat.
1374
-
1375
- ```python
1376
- message = unique_sdk.Space.create_message(
1377
- user_id=user_id,
1378
- company_id=company_id,
1379
- chatId="chat_dejfhe729br398", # Optional - if not provided, a new chat will be created
1380
- assistantId="assistant_abc123",
1381
- text="Hello, how can you help me?",
1382
- toolChoices=["WebSearch"], # Optional - list of tools to use
1383
- scopeRules={ # Optional - scope rules for filtering
1384
- "or": [
1385
- {
1386
- "operator": "contains",
1387
- "path": ["folderIdPath"],
1388
- "value": "uniquepathid://scope_123"
1389
- }
1390
- ]
1391
- },
1392
- )
1393
- ```
1394
-
1395
- #### `unique_sdk.Space.get_chat_messages` (Compatible with release >.48)
1396
-
1397
- Get all messages in a space chat. Returns a list of paginated messages in the specified chat.
1398
-
1399
- ```python
1400
- messages = unique_sdk.Space.get_chat_messages(
1401
- user_id=user_id,
1402
- company_id=company_id,
1403
- chat_id="chat_dejfhe729br398",
1404
- skip=0, # Optional (defaults to 0) - number of messages to skip for pagination
1405
- take=50, # Optional (defaults to 10) - number of messages to return
1406
- )
1407
- ```
1408
-
1409
- #### `unique_sdk.Space.get_latest_message`
1410
-
1411
- Get the latest message in a space chat.
1412
-
1413
- ```python
1414
- message = unique_sdk.Space.get_latest_message(
1415
- user_id=user_id,
1416
- company_id=company_id,
1417
- chat_id="chat_dejfhe729br398",
1418
- )
1419
- ```
1420
-
1421
- #### `unique_sdk.Space.delete_chat`
1422
-
1423
- Delete a space chat by id. If the chat does not exist, the function will return an error.
1424
-
1425
- ```python
1426
- unique_sdk.Space.delete_chat(
1427
- user_id=user_id,
1428
- company_id=company_id,
1429
- chat_id="chat_dejfhe729br398",
1430
- )
1431
- ```
1432
-
1433
- ### LLM Models
1434
-
1435
- #### `unique_sdk.LLMModels.get` (Compatible with release >.46)
1436
-
1437
- Get available LLM models. You can optionally filter by module and skip cache to fetch fresh data.
1438
-
1439
- ```python
1440
- models = unique_sdk.LLMModels.get(
1441
- user_id=user_id,
1442
- company_id=company_id,
1443
- module="UNIQUE_AI", # Optional - filter models by module, only UNIQUE_AI is supported right now
1444
- )
1445
- ```
1446
-
1447
- ### User
1448
-
1449
- #### `unique_sdk.User.get_users` (Compatible with release >.48)
1450
-
1451
- Get users in a company. You can filter by email, display name, and use pagination with skip and take parameters.
1452
-
1453
- ```python
1454
- users = unique_sdk.User.get_users(
1455
- user_id=user_id,
1456
- company_id=company_id,
1457
- skip=0, # Optional - number of records to skip for pagination
1458
- take=50, # Optional - number of records to return (max 1000)
1459
- email="user@example.com", # Optional - filter by email
1460
- displayName="John", # Optional - filter by display name
1461
- )
1462
- ```
1463
-
1464
- ### Group
1465
-
1466
- #### `unique_sdk.Group.create_group` (Compatible with release >.48)
1467
-
1468
- Create a new group in a company. You can specify the group name (required), external ID and parent group ID.
1469
-
1470
- ```python
1471
- group = unique_sdk.Group.create_group(
1472
- user_id=user_id,
1473
- company_id=company_id,
1474
- name="New Group", # Required - the name of the group
1475
- externalId="ext_123", # Optional - external ID for the group
1476
- parentId="group_a9cs7wr2z1bg2sxczvltgjch", # Optional - parent group ID
1477
- )
1478
- ```
1479
-
1480
- #### `unique_sdk.Group.get_groups` (Compatible with release >.48)
1481
-
1482
- Get groups in a company. You can filter by name and use pagination with skip and take parameters.
1483
-
1484
- ```python
1485
- groups = unique_sdk.Group.get_groups(
1486
- user_id=user_id,
1487
- company_id=company_id,
1488
- skip=0, # Optional - number of records to skip for pagination
1489
- take=50, # Optional - number of records to return (max 1000)
1490
- name="Admin", # Optional - filter by group name
1491
- )
1492
- ```
1493
-
1494
- #### `unique_sdk.Group.update_group` (Compatible with release >.48)
1495
-
1496
- Update a group in a company. You can update the group's name.
1497
-
1498
- ```python
1499
- updated_group = unique_sdk.Group.update_group(
1500
- user_id=user_id,
1501
- company_id=company_id,
1502
- group_id="group_a9cs7wr2z1bg2sxczvltgjch",
1503
- name="New Group Name", # Optional - update the group name
1504
- )
1505
- ```
1506
-
1507
- #### `unique_sdk.Group.add_users_to_group` (Compatible with release >.48)
1508
-
1509
- Add users to a group. Provide an array of user IDs to add as members to the specified group.
1510
-
1511
- ```python
1512
- result = unique_sdk.Group.add_users_to_group(
1513
- user_id=user_id,
1514
- company_id=company_id,
1515
- group_id="group_a9cs7wr2z1bg2sxczvltgjch",
1516
- userIds=["299420877169688584", "325402458132058201", "299426678160031752"], # Required - array of user IDs to add
1517
- )
1518
- ```
1519
-
1520
- #### `unique_sdk.Group.remove_users_from_group` (Compatible with release >.48)
1521
-
1522
- Remove users from a group. Provide an array of user IDs to remove from the specified group.
1523
-
1524
- ```python
1525
- result = unique_sdk.Group.remove_users_from_group(
1526
- user_id=user_id,
1527
- company_id=company_id,
1528
- group_id="group_a9cs7wr2z1bg2sxczvltgjch",
1529
- userIds=["299426678160031752", "299426678160031752"], # Required - array of user IDs to remove
1530
- )
1531
- ```
1532
-
1533
- #### `unique_sdk.Group.delete_group` (Compatible with release >.48)
1534
-
1535
- Delete a group in a company by its group ID.
1536
-
1537
- ```python
1538
- result = unique_sdk.Group.delete_group(
1539
- user_id=user_id,
1540
- company_id=company_id,
1541
- group_id="group_a9cs7wr2z1bg2sxczvltgjch",
1542
- )
1543
- ```
1544
-
1545
- ### Agentic Table
1546
-
1547
- The Agentic Table (Magic Table) API provides functionality for managing interactive tables with AI-powered cells, activity tracking, and metadata management.
1548
-
1549
- #### `unique_sdk.AgenticTable.set_cell`
1550
-
1551
- Set the content of a specific cell in the magic table. This method allows you to update cell text and optionally add log entries to track changes.
1552
-
1553
- ```python
1554
- cell = await unique_sdk.AgenticTable.set_cell(
1555
- user_id=user_id,
1556
- company_id=company_id,
1557
- tableId="sheet_abc123",
1558
- rowOrder=0,
1559
- columnOrder=1,
1560
- text="Updated cell content",
1561
- logEntries=[ # optional
1562
- {
1563
- "text": "Cell updated by automation",
1564
- "createdAt": "2024-01-01T00:00:00.000Z",
1565
- "actorType": "SYSTEM", # One of: "USER", "SYSTEM", "ASSISTANT", "TOOL"
1566
- "messageId": "msg_123", # optional
1567
- "details": [ # optional
1568
- {
1569
- "text": "Processing completed",
1570
- "messageId": "msg_456" # optional
1571
- }
1572
- ]
1573
- }
1574
- ]
1575
- )
1576
- ```
1577
-
1578
- #### `unique_sdk.AgenticTable.get_cell`
1579
-
1580
- Retrieve the content and metadata of a specific cell.
1581
-
1582
- ```python
1583
- cell = await unique_sdk.AgenticTable.get_cell(
1584
- user_id=user_id,
1585
- company_id=company_id,
1586
- tableId="sheet_abc123",
1587
- rowOrder=0,
1588
- columnOrder=1,
1589
- )
1590
- ```
1591
-
1592
- #### `unique_sdk.AgenticTable.set_multiple_cells`
1593
-
1594
- Bulk update multiple cells in a single operation for better performance.
1595
-
1596
- ```python
1597
- result = await unique_sdk.AgenticTable.set_multiple_cells(
1598
- user_id=user_id,
1599
- company_id=company_id,
1600
- tableId="sheet_abc123",
1601
- cells=[
1602
- {
1603
- "rowOrder": 0,
1604
- "columnOrder": 0,
1605
- "text": "Cell A1"
1606
- },
1607
- {
1608
- "rowOrder": 0,
1609
- "columnOrder": 1,
1610
- "text": "Cell B1"
1611
- },
1612
- {
1613
- "rowOrder": 1,
1614
- "columnOrder": 0,
1615
- "text": "Cell A2"
1616
- }
1617
- ]
1618
- )
1619
- ```
1620
-
1621
- #### `unique_sdk.AgenticTable.get_sheet_data`
1622
-
1623
- Retrieve comprehensive data about a magic table sheet, including cells, log history, and metadata.
1624
-
1625
- ```python
1626
- sheet = await unique_sdk.AgenticTable.get_sheet_data(
1627
- user_id=user_id,
1628
- company_id=company_id,
1629
- tableId="sheet_abc123",
1630
- includeCells=True, # optional
1631
- includeLogHistory=True, # optional
1632
- includeRowCount=True, # optional
1633
- includeCellMetaData=True, # optional
1634
- startRow=0, # optional: specify row range
1635
- endRow=10 # optional: specify row range
1636
- )
1637
- ```
1638
-
1639
- #### `unique_sdk.AgenticTable.get_sheet_state`
1640
-
1641
- Get the current state of a magic table sheet.
1642
-
1643
- ```python
1644
- state = await unique_sdk.AgenticTable.get_sheet_state(
1645
- user_id=user_id,
1646
- company_id=company_id,
1647
- tableId="sheet_abc123"
1648
- )
1649
- # Returns: "PROCESSING", "IDLE", or "STOPPED_BY_USER"
1650
- ```
1651
-
1652
- #### `unique_sdk.AgenticTable.update_sheet_state`
1653
-
1654
- Update the name or state of a magic table sheet.
1655
-
1656
- ```python
1657
- result = await unique_sdk.AgenticTable.update_sheet_state(
1658
- user_id=user_id,
1659
- company_id=company_id,
1660
- tableId="sheet_abc123",
1661
- name="Updated Sheet Name", # optional
1662
- state="IDLE" # optional, one of: "PROCESSING", "IDLE", "STOPPED_BY_USER"
1663
- )
1664
- ```
1665
-
1666
- #### `unique_sdk.AgenticTable.set_activity`
1667
-
1668
- Set the status of an activity on the magic table sheet. This is useful for tracking long-running operations.
1669
-
1670
- ```python
1671
- result = await unique_sdk.AgenticTable.set_activity(
1672
- user_id=user_id,
1673
- company_id=company_id,
1674
- tableId="sheet_abc123",
1675
- activity="UpdateCell",
1676
- # activity: one of "DeleteRow", "DeleteColumn", "UpdateCell", "AddQuestionText",
1677
- # "AddMetaData", "GenerateArtifact", "SheetCompleted", "LibrarySheetRowVerified"
1678
- status="IN_PROGRESS",
1679
- # status: one of "IN_PROGRESS", "COMPLETED", "FAILED"
1680
- text="Updating cells with AI-generated content"
1681
- )
1682
- ```
1683
-
1684
- #### `unique_sdk.AgenticTable.set_artifact`
1685
-
1686
- Attach an artifact (such as a generated document) to the magic table sheet.
1687
-
1688
- ```python
1689
- result = await unique_sdk.AgenticTable.set_artifact(
1690
- user_id=user_id,
1691
- company_id=company_id,
1692
- tableId="sheet_abc123",
1693
- name="Generated Report",
1694
- contentId="cont_xyz789",
1695
- mimeType="application/pdf",
1696
- artifactType="FULL_REPORT" # One of: "QUESTIONS", "FULL_REPORT"
1697
- )
1698
- ```
1699
-
1700
- #### `unique_sdk.AgenticTable.set_column_metadata`
1701
-
1702
- Configure metadata for a specific column, including width, filters, and cell renderers.
1703
-
1704
- ```python
1705
- result = await unique_sdk.AgenticTable.set_column_metadata(
1706
- user_id=user_id,
1707
- company_id=company_id,
1708
- tableId="sheet_abc123",
1709
- columnOrder=2,
1710
- columnWidth=200, # optional
1711
- filter="ValueMatchFilter", # optional
1712
- # filter: one of "ValueMatchFilter", "PartialMatchFilter", "ReferenceFilter",
1713
- # "HallucinationFilter", "ReviewStatusFilter", "AssigneeFilter"
1714
- cellRenderer="CheckboxLockCellRenderer", # optional
1715
- # cellRenderer: one of "CheckboxLockCellRenderer", "CollaboratorDropdown",
1716
- # "ReviewStatusDropdown", "CustomCellRenderer", "SelectableCellRenderer"
1717
- editable=True # optional
1718
- )
1719
- ```
1720
-
1721
- #### `unique_sdk.AgenticTable.set_cell_metadata`
1722
-
1723
- Set metadata for a specific cell, including selection status and agreement status.
1724
-
1725
- ```python
1726
- result = await unique_sdk.AgenticTable.set_cell_metadata(
1727
- user_id=user_id,
1728
- company_id=company_id,
1729
- tableId="sheet_abc123",
1730
- rowOrder=0,
1731
- columnOrder=1,
1732
- selected=True, # optional
1733
- selectionMethod="MANUAL", # optional, one of: "DEFAULT", "MANUAL"
1734
- agreementStatus="MATCH" # optional, one of: "MATCH", "NO_MATCH"
1735
- )
1736
- ```
1737
-
1738
- #### `unique_sdk.AgenticTable.bulk_update_status`
1739
-
1740
- Update the verification status of multiple rows at once.
1741
-
1742
- ```python
1743
- result = await unique_sdk.AgenticTable.bulk_update_status(
1744
- user_id=user_id,
1745
- company_id=company_id,
1746
- tableId="sheet_abc123",
1747
- rowOrders=[0, 1, 2, 3, 4],
1748
- status="VERIFIED"
1749
- # status: one of "NEED_REVIEW", "READY_FOR_VERIFICATION", "VERIFIED"
1750
- )
1751
- ```
1752
-
1753
- ## UniqueQL
1754
-
1755
- [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.
1756
-
1757
- ### UniqueQL Query Structure
1758
-
1759
- 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.
1760
-
1761
- A metadata filter can be designed with UniqueQL's `UQLOperator` and `UQLCombinator` as follows:
1762
-
1763
- ```python
1764
- metadata_filter = {
1765
- "path": ['diet', '*'],
1766
- "operator": UQLOperator.NESTED,
1767
- "value": {
1768
- UQLCombinator.OR : [
1769
- {
1770
- UQLCombinator.OR: [
1771
- {
1772
- "path": ['food'],
1773
- "operator": UQLOperator.EQUALS,
1774
- "value": "meat",
1775
- },
1776
- {
1777
- "path": ['food'],
1778
- "operator": UQLOperator.EQUALS,
1779
- "value": 'vegis',
1780
- },
1781
- ],
1782
- },
1783
- {
1784
- "path": ['likes'],
1785
- "operator": UQLOperator.EQUALS,
1786
- "value": true,
1787
- },
1788
- ],
1789
- },
1790
- }
1791
- ```
1792
-
1793
- ### Metadata Filtering
1794
-
1795
- A metadata filter such as the one designed above can be used in a `Search.create` call by passing it the `metaDataFilter` parameter.
1796
-
1797
- ```python
1798
- search_results = unique_sdk.Search.create(
1799
- user_id=user_id,
1800
- company_id=company_id,
1801
- chatId=chat_id,
1802
- searchString=search_string,
1803
- searchType="COMBINED",
1804
- # limit=2,
1805
- metaDataFilter=metadata_filter,
1806
- )
1807
- ```
1808
-
1809
- ## Utils
1810
-
1811
- - [Chat History](#chat-history)
1812
- - [File Io](#file-io)
1813
- - [Sources](#sources)
1814
- - [token](#token)
1815
- - [Chat In Space](#chat-in-space)
1816
-
1817
- ### Chat History
1818
-
1819
- #### `unique_sdk.utils.chat_history.load_history`
1820
-
1821
- 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.
1822
-
1823
- - `maxTokens` max tokens of the model used
1824
- - `percentOfMaxTokens`=0.15 % max history in % of `maxTokens`
1825
- - `maxMessages`=4, maximal number of messages included in the history.
1826
-
1827
- this method also directly returns a correct formatted history that can be used in the next chat round.
1828
-
1829
- ```python
1830
- history = unique_sdk.utils.chat_history.load_history(
1831
- userId,
1832
- companyId,
1833
- chatId
1834
- )
1835
- ```
1836
-
1837
- #### `unique_sdk.utils.chat_history.convert_chat_history_to_injectable_string`
1838
-
1839
- convert history into a string that can be injected into a prompt. it als returns the token length of the converted history.
1840
-
1841
- ```
1842
- chat_history-string, chat_context_token_length = unique_sdk.utils.chat_history.convert_chat_history_to_injectable_string(
1843
- history
1844
- )
1845
- ```
1846
-
1847
- ### File Io
1848
-
1849
- Interacting with the knowledge-base.
1850
-
1851
- #### `unique_sdk.utils.file_io.download_content`
1852
-
1853
- download files and save them into a folder in `/tmp`
1854
-
1855
- for example using the readUrl from a content.
1856
-
1857
- ```python
1858
- pdfFile = download_content(
1859
- companyId=companyId,
1860
- userId=userId,
1861
- content_id="cont_12412",
1862
- filename="hello.pdf",
1863
- chat_id=None # If specified, it downloads it from the chat
1864
- )
1865
- ```
1866
-
1867
- #### `unique_sdk.utils.file_io.upload_file`
1868
-
1869
- Allows for uploading files that then get ingested in a scope or a chat.
1870
-
1871
- ```python
1872
- createdContent = upload_file(
1873
- companyId=companyId,
1874
- userId=userId,
1875
- path_to_file="/tmp/hello.pdf",
1876
- displayed_filename="hello.pdf",
1877
- mime_type="application/pdf",
1878
- scope_or_unique_path="scope_stcj2osgbl722m22jayidx0n",
1879
- chat_id=None,
1880
- )
1881
- ```
1882
-
1883
- ### Sources
1884
-
1885
- #### `unique_sdk.utils.sources.merge_sources`
1886
-
1887
- Merges multiple search results based on their 'id', removing redundant document and info markers.
1888
-
1889
- This function groups search results by their 'id' and then concatenates their texts,
1890
- cleaning up any document or info markers in subsequent chunks beyond the first one.
1891
-
1892
- Parameters:
1893
-
1894
- - searchContext (list): A list of dictionaries, each representing a search result with 'id' and 'text' keys.
1895
-
1896
- Returns:
1897
-
1898
- - list: A list of dictionaries with merged texts for each unique 'id'.
1899
-
1900
- `searchContext` is an list of search objects that are returned by the search.
1901
-
1902
- ```python
1903
- search = unique_sdk.Search.create(
1904
- user_id=userId,
1905
- company_id=companyId,
1906
- chatId=chatId,
1907
- searchString="Who is Harry P?",
1908
- searchType="COMBINED",
1909
- scopeIds="scope_dsf...",
1910
- limit=30,
1911
- chatOnly=False,
1912
- )
1913
-
1914
- searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
1915
- search["data"], config["maxTokens"] - historyLength
1916
- )
1917
-
1918
- searchContext = unique_sdk.utils.sources.merge_sources(search)
1919
-
1920
- ```
1921
-
1922
- #### `unique_sdk.utils.sources.sort_sources`
1923
-
1924
- Sort sources by order of appearance in documents
1925
-
1926
- ```python
1927
-
1928
- search = unique_sdk.Search.create(
1929
- user_id=userId,
1930
- company_id=companyId,
1931
- chatId=chatId,
1932
- searchString="Who is Harry P?",
1933
- searchType="COMBINED",
1934
- scopeIds="scope_dsf...",
1935
- limit=30,
1936
- chatOnly=False,
1937
- )
1938
-
1939
- searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
1940
- search["data"], config["maxTokens"] - historyLength
1941
- )
1942
-
1943
- searchContext = unique_sdk.utils.sources.sort_sources(search)
1944
- ```
1945
-
1946
- #### `unique_sdk.utils.sources.post_process_sources`
1947
-
1948
- Post-processes the provided text by converting source references into superscript numerals (required
1949
- format by backend to display sources in the chat window)
1950
-
1951
- This function searches the input text for patterns that represent source references (e.g., [source1])
1952
- and replaces them with superscript tags, incrementing the number by one.
1953
-
1954
- Parameters:
1955
-
1956
- - text (str): The text to be post-processed.
1957
-
1958
- Returns:
1959
-
1960
- - str: The text with source references replaced by superscript numerals.
1961
-
1962
- Examples:
1963
-
1964
- - postprocessSources("This is a reference [source0]") will return "This is a reference <sup>1</sup>".
1965
-
1966
- ```python
1967
-
1968
- text_with_sup = post_process_sources(text)
1969
- ```
1970
-
1971
- ### Token
1972
-
1973
- #### unique_sdk.utils.token.pick_search_results_for_token_window
1974
-
1975
- Selects and returns a list of search results that fit within a specified token limit.
1976
-
1977
- This function iterates over a list of search results, each with a 'text' field, and
1978
- encodes the text using a predefined encoding scheme. It accumulates search results
1979
- until the token limit is reached or exceeded.
1980
-
1981
- Parameters:
1982
-
1983
- - searchResults (list): A list of dictionaries, each containing a 'text' key with string value.
1984
- - tokenLimit (int): The maximum number of tokens to include in the output.
1985
-
1986
- Returns:
1987
-
1988
- - list: A list of dictionaries representing the search results that fit within the token limit.
1989
-
1990
- ```python
1991
- search = unique_sdk.Search.create(
1992
- user_id=userId,
1993
- company_id=companyId,
1994
- chatId=chatId,
1995
- searchString="Who is Harry P?",
1996
- searchType="COMBINED",
1997
- scopeIds="scope_dsf...",
1998
- limit=30,
1999
- chatOnly=False,
2000
- )
2001
-
2002
- searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
2003
- search["data"], config["maxTokens"] - historyLength
2004
- )
2005
- ```
2006
-
2007
- #### unique_sdk.utils.token.count_tokens
2008
-
2009
- Counts the number of tokens in the provided text.
2010
-
2011
- This function encodes the input text using a predefined encoding scheme
2012
- and returns the number of tokens in the encoded text.
2013
-
2014
- Parameters:
2015
-
2016
- - text (str): The text to count tokens for.
2017
-
2018
- Returns:
2019
-
2020
- - int: The number of tokens in the text.
2021
-
2022
- ```python
2023
- hello = "hello you!"
2024
- searchContext = unique_sdk.utils.token.count_tokens(hello)
2025
- ```
2026
-
2027
- ### Chat In Space
2028
-
2029
- #### `unique_sdk.utils.chat_in_space.send_message_and_wait_for_completion`
2030
-
2031
- 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.
2032
-
2033
- The script sends a prompt asynchronously and continuously polls for completion, which is determined when the `stoppedStreamingAt` field of the message becomes non-null.
2034
-
2035
- **Optional parameters:**
2036
- - `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`.
2037
- - `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.
2038
- - `chat_id`: The ID of the chat where the message should be sent. If omitted, a new chat will be created.
2039
- - `poll_interval`: The number of seconds to wait between polling attempts (default: `1` second).
2040
- - `max_wait`: The maximum number of seconds to wait for the message to complete (default: `60` seconds).
2041
- - `stop_condition`: Defines when to expect a response back, when the assistant stop streaming or when it completes the message. (default: "stoppedStreamingAt")
2042
-
2043
- The script ensures you can flexibly interact with spaces in new or ongoing chats, with fine-grained control over tools, context, and polling behavior.
2044
-
2045
- ```python
2046
- from unique_sdk.utils.chat_in_space import send_message_and_wait_for_completion
2047
- latest_message = await send_message_and_wait_for_completion(
2048
- user_id=user_id,
2049
- company_id=company_id,
2050
- assistant_id=assistant_id,
2051
- text="Tell me a short story.",
2052
- chat_id=chat_id, # Optional - if no chat id is specified, a new chat will be created
2053
- tool_choices=["WebSearch"],
2054
- scope_rules={
2055
- "or": [
2056
- {
2057
- "operator": "in",
2058
- "path": [
2059
- "contentId"
2060
- ],
2061
- "value": [
2062
- "cont_u888z7cazxxm4lugfdjq7pks"
2063
- ]
2064
- },
2065
- {
2066
- "operator": "contains",
2067
- "path": [
2068
- "folderIdPath"
2069
- ],
2070
- "value": "uniquepathid://scope_btfo28b3eeelwh5obwgea71bl/scope_fn56ta67knd6w4medgq3028fx"
2071
- }
2072
- ]
2073
- },
2074
- stop_condition = "completedAt" # If not specified, stoppedStreamingAt will be set by default
2075
- )
2076
- ```
2077
-
2078
- #### `unique_sdk.utils.chat_in_space.chat_against_file`
2079
-
2080
- The following script enables you to chat against a file.
2081
-
2082
- You must provide the following parameters:
2083
- - `assistantId`: The assistant to be used for the chat.
2084
- - `path_to_file`: The local path of the file to be uploaded.
2085
- - `displayed_filename`: The name of the file to be displayed.
2086
- - `mime_type`: The mime type of the ifle to be uploaded.
2087
- - `text`: The text to be sent to the chat for chatting against the file.
2088
-
2089
- 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. The function deletes the chat at the end unless the `should_delete_chat` is set to false.
2090
-
2091
- **Optional parameters:**
2092
- - `poll_interval`: The number of seconds to wait between polling attempts (default: `1` second).
2093
- - `max_wait`: The maximum number of seconds to wait for the message to complete (default: `60` seconds).
2094
- - `should_delete_chat`: Setting this flag determines whether the chat should be deleted at the end or not. Default is True.
2095
-
2096
- Example of chatting against a PDF. (The usage can be extended to any supported file type)
2097
-
2098
- ```python
2099
- latest_message = await unique_sdk.utils.chat_in_space.chat_against_file(
2100
- user_id=user_id,
2101
- company_id=company_id,
2102
- assistant_id="assistant_hjcdga64bkcjnhu4",
2103
- path_to_file="/files/hello.pdf",
2104
- displayed_filename="hello.pdf",
2105
- mime_type="application/pdf",
2106
- text="Give me a bullet point summary of the file.",
2107
- )
2108
- ```
2109
-
2110
- #### `unique_sdk.utils.chat_in_space.wait_for_ingestion_completion`
2111
-
2112
- 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`.
2113
-
2114
- You must provide the following parameter:
2115
- - `content_id`: The id of the content to check.
2116
-
2117
- 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.
2118
-
2119
- **Optional parameters:**
2120
- - `chat_id`: In case the content is uploaded to a chat, the `chat_id` must be provided.
2121
- - `poll_interval`: The number of seconds to wait between polling attempts (default: `1` second).
2122
- - `max_wait`: The maximum number of seconds to wait for the message to complete (default: `60` seconds).
2123
-
2124
- Example of waiting for the ingestion of a file in the Knowledge Base.
2125
-
2126
- ```python
2127
- await unique_sdk.utils.chat_in_space.wait_for_ingestion_completion(
2128
- user_id=user_id,
2129
- company_id=company_id,
2130
- content_id="cont_ddlezvag4kzxudfr24lrjc5mx",
2131
- )
2132
- ```
2133
-
2134
- ## Error Handling
2135
-
2136
- ## Examples
2137
-
2138
- 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`.
2139
-
2140
- ## Credits
2141
-
2142
- This is a _fork_ / inspired-by the fantastic Stripe Python SDK (https://github.com/stripe/stripe-python).
2143
-
2144
- # Changelog
2145
-
2146
- All notable changes to this project will be documented in this file.
2147
-
2148
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
2149
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
2150
-
2151
- ## [0.10.47] - 2025-11-19
2152
- - Add expired/s at fields on content search result.
2153
-
2154
- ## [0.10.46] - 2025-11-18
2155
- - chat_against_file function allows now a should_delete_chat flag.
2156
-
2157
- ## [0.10.45] - 2025-11-18
2158
- - Create group and manage users functions.
2159
-
2160
- ## [0.10.44] - 2025-11-18
2161
- - add function to get all messages in a chat.
2162
-
2163
- ## [0.10.43] - 2025-11-14
2164
- - Add get, delete and update groups functions.
2165
-
2166
- ## [0.10.42] - 2025-11-14
2167
- - Add get_users function.
2168
-
2169
- ## [0.10.41] - 2025-11-13
2170
- - Add create_message and get_latest_message.
2171
-
2172
- ## [0.10.40] - 2025-11-10
2173
- - Don't send description if not defined.
2174
-
2175
- ## [0.10.39] - 2025-11-07
2176
- - Add function to get llm models
2177
-
2178
- ## [0.10.38] - 2025-11-06
2179
- - Add description property to Reference and Content.
2180
-
2181
- ## [0.10.37] - 2025-11-04
2182
- - Introduce local integration tests for Content API Resource
2183
-
2184
- ## [0.10.36] - 2025-11-04
2185
- - Introduce local integration tests for Folder API Resource
2186
-
2187
- ## [0.10.35] - 2025-11-04
2188
- - Inmprove folder get infos types.
2189
-
2190
- ## [0.10.34] - 2025-10-29
2191
- - Add documentation for agentic table.
2192
-
2193
- ## [0.10.33] - 2025-10-27
2194
- - Improve messagelog and message execution types.
2195
-
2196
- ## [0.10.32] - 2025-10-14
2197
- - Add function to stream to chat frontend.
2198
-
2199
- ## [0.10.31] - 2025-10-13
2200
- - Add readme for message log and execution.
2201
-
2202
- ## [0.10.30] - 2025-10-07
2203
- - Improve types for content get infos.
2204
-
2205
- ## [0.10.29] - 2025-10-06
2206
- - Switch default model used from `GPT-3.5-turbo (0125)` to `GPT-4o (1120)`
2207
-
2208
- ## [0.10.28] - 2025-10-03
2209
- - Use non blocking versions of `Space.get_latest_message` and `Message.retrieve` in `send_message_and_wait_for_completion`.
2210
-
2211
- ## [0.10.27] - 2025-09-24
2212
- - Improve readme to use Unique AI.
2213
-
2214
- ## [0.10.26] - 2025-09-22
2215
- - Improve typing.
2216
-
2217
- ## [0.10.25] - 2025-09-18
2218
- - Add support for udpate and delete files by file or folder path.
2219
-
2220
- ## [0.10.24] - 2025-09-17
2221
- - Add function to update a folder.
2222
-
2223
- ## [0.10.23] - 2025-09-12
2224
- - Revert to using default reasoning effort.
2225
-
2226
- ## [0.10.22] - 2025-09-12
2227
- - Add support for metadata update of a file.
2228
-
2229
- ## [0.10.21] - 2025-09-04
2230
- - Update Chat Completions API types and add support for reasoning effort.
2231
-
2232
- ## [0.10.20] - 2025-09-04
2233
- - Update Responses API types
2234
-
2235
- ## [0.10.19] - 2025-09-02
2236
- - Improve `send_message_and_wait_for_completion`:
2237
- - Add option to select stop_condition `["stoppedStreamingAt", "completedAt"]`.
2238
- - Load `debugInfo` from `last_user_message` for better developer experience.
2239
-
2240
- ## [0.10.18] - 2025-09-02
2241
- - Temporarily remove support for update and delete files by filePath.
2242
-
2243
- ## [0.10.17] - 2025-09-01
2244
- - Add function to update a file
2245
-
2246
- ## [0.10.16] - 2025-08-31
2247
- - Add function to delete a content.
2248
-
2249
- ## [0.10.15] - 2025-08-28
2250
- - Add default values for message log types
2251
-
2252
- ## [0.10.14] - 2025-08-28
2253
- - Add function to delete folders and files recursively
2254
-
2255
- ## [0.10.13] - 2025-08-24
2256
- - Add functions to create, get and update a message eecution and create and update a message log.
2257
-
2258
- ## [0.10.12] - 2025-08-24
2259
- - Switch to using Content get info deprecated endpoint to make sure we support older release versions.
2260
-
2261
- ## [0.10.11] - 2025-08-24
2262
- - Enforce usage of ruff using pipeline
2263
-
2264
- ## [0.10.10] - 2025-08-18
2265
- - Fix wrong name of references in `Space.Message`.
2266
- - Fix wrong name of assessment in `Space.Message`.
2267
- - Remove default values for `text`, `originalText` and `debugInfo` in `Space.Message` as these don't have an effect.
2268
-
2269
- ## [0.10.9] - 2025-08-15
2270
- - Add script to wait for content ingestion finished.
2271
-
2272
- ## [0.10.8] - 2025-08-13
2273
- - Add support for Agentic Table.
2274
-
2275
- ## [0.10.7] - 2025-08-13
2276
- - Make metadata optional when uploading a file.
2277
-
2278
- ## [0.10.6] - 2025-08-06
2279
- - Make tools optional for running an agent.
2280
-
2281
- ## [0.10.5] - 2025-08-06
2282
- - Get paginated files and folders info.
2283
-
2284
- ## [0.10.4] - 2025-08-05
2285
- - Add support for reasoning API with streaming within a chat.
2286
-
2287
- ## [0.10.3] - 2025-08-05
2288
- - Expose scoreThreshold param for search.
2289
-
2290
- ## [0.10.2] - 2025-08-05
2291
- - Add script to chat against file.
2292
-
2293
- ## [0.10.1] - 2025-08-05
2294
- - Allow deletion of a space chat.
2295
-
2296
- ## [0.10.0] - 2025-08-04
2297
- - Add MCP support
2298
-
2299
- ## [0.9.42] - 2025-07-31
2300
- - Fix wrong chat in space example.
2301
-
2302
- ## [0.9.41] - 2025-07-31
2303
- - Fix double-slash error in open ai proxy script.
2304
-
2305
- ## [0.9.40] - 2025-07-22
2306
- - Fixed bug where get requests send body with the request. This is not allowed by WAF policies.
2307
-
2308
- ## [0.9.39] - 2025-07-18
2309
- - Add script to chat in a space.
2310
-
2311
- ## [0.9.38] - 2025-07-18
2312
- - [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`.
2313
-
2314
- ## [0.9.37] - 2025-07-10
2315
- - Add `sheetName` property to the `MagicTableSheetIngestParams` object used by function that ingests magic table sheets.
2316
-
2317
- ## [0.9.36] - 2025-06-23
2318
- - Allow passing a user id when creating chat completions. This is optional and it does not impact the current behaviour.
2319
-
2320
- ## [0.9.35] - 2025-06-18
2321
- - Allow scope access updates (add/remove) on folder based on scope id or path.
2322
-
2323
- ## [0.9.34] - 2025-06-17
2324
- - Allow ingestion config updates on folder based on scope id or path.
2325
-
2326
- ## [0.9.33] - 2025-06-11
2327
- - Add function to get a folder by id or by path.
2328
-
2329
- ## [0.9.32] - 2025-06-11
2330
- - Add function to ingest magic table sheets.
2331
-
2332
- ## [0.9.31] - 2025-05-21
2333
- - Add function to update folder access (add or remove).
2334
-
2335
- ## [0.9.30] - 2025-05-21
2336
- - Add function to update folder ingestion config.
2337
-
2338
- ## [0.9.29] - 2025-05-20
2339
- - Add function to create folder paths if they do not exist.
2340
-
2341
- ## [0.9.28] - 2025-05-20
2342
- - Add function to search content info. This also allows filtering content info by metadata info.
2343
-
2344
- ## [0.9.27] - 2025-05-14
2345
- - Add the possibility to specify metadata when creating or updating a Content.
2346
-
2347
- ## [0.9.26] - 2025-05-13
2348
- - Add the possibility to specify ingestionConfig when creating or updating a Content.
2349
-
2350
- ## [0.9.25] - 2025-05-02
2351
- - Fixed typos in `README.md`, including incorrect `sdk.utils` imports and code example errors.
2352
-
2353
- ## [0.9.24] - 2025-04-23
2354
- - Make `chatId` property in `Search.CreateParams` optional
2355
-
2356
- ## [0.9.23] - 2025-03-25
2357
- - Define programming language classifier explicitly for python 3.11
2358
-
2359
- ## [0.9.22] - 2025-02-25
2360
- - update the retry_on_error to only `APIError` and `APIConnectionError` update the `resp["error"]` to be `resp.get("error")` to avoid key error
2361
-
2362
- ## [0.9.21] - 2025-02-21
2363
- - Add title parameter and change labels in `MessageAssessment`
2364
-
2365
- ## [0.9.20] - 2025-02-01
2366
- - Add url parameter to `MessageAssessment.create_async` and `MessageAssessment.modify_async`
2367
-
2368
- ## [0.9.19] - 2025-01-31
2369
- - Add `MessageAssessment` resource
2370
-
2371
- ## [0.9.18] - 2025-01-22
2372
- - Removed `Invalid response body from API` from `retry_dict` as it's our own artificail error.
2373
-
2374
- ## [0.9.17] - 2025-01-03
2375
- - BREAKING CHANGE!! Removed unused `id` from `ShortTermMemory` create and find methods.
2376
-
2377
- ## [0.9.16] - 2024-12-19
2378
- - Corrected return type of `Search.create` and `Search.create_async` to `List[Search]`
2379
- - Retry on `Connection aborted` error
2380
-
2381
- ## [0.9.15] - 2024-12-06
2382
- - Add `Internal server error` and `You can retry your request` to the retry logic
2383
-
2384
- ## [0.9.14] - 2024-12-06
2385
- - Add `contentIds` to `Search.create` and `Search.create_async`
2386
-
2387
- ## [0.9.13] - 2024-10-23
2388
- - Add retry for `5xx` errors, add additional error message.
2389
-
2390
- ## [0.9.12] - 2024-11-21
2391
- - Include original error message in returned exceptions
2392
-
2393
- ## [0.9.11] - 2024-11-18
2394
- - Add `ingestionConfig` to `UpsertParams.Input` parameters
2395
-
2396
- ## [0.9.10] - 2024-10-23
2397
- - 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.
2398
-
2399
- ## [0.9.9] - 2024-10-23
2400
- - Revert deletion of `Message.retrieve` method
2401
-
2402
- ## [0.9.8] - 2024-10-16
2403
- - Add `retries` for `_static_request` and `_static_request_async` in `APIResource` - When the error messages contains either `"problem proxying the request"`,
2404
- or `"Upstream service reached a hard timeout"`,
2405
- ## [0.9.7] - 2024-09-23
2406
- - Add `completedAt` to `CreateParams` of `Message`
2407
-
2408
- ## [0.9.6] - 2024-09-03
2409
- - Added `metaDataFilter` to `Search` parameters.
2410
-
2411
- ## [0.9.5] - 2024-08-07
2412
- - Add `completedAt` to `ModifyParams`
2413
-
2414
- ## [0.9.4] - 2024-07-31
2415
- - Add `close` and `close_async` to `http_client`
2416
- - Make `httpx` the default client for async requests
2417
-
2418
- ## [0.9.3] - 2024-07-31
2419
- - `Search.create`, `Message`, `ChatCompletion` parameters that were marked `NotRequired` are now also `Optional`
2420
-
2421
- ## [0.9.2] - 2024-07-30
2422
- - Bug fix in `Search.create`: langugage -> language
2423
-
2424
- ## [0.9.1] - 2024-07-30
2425
- - Added parameters to `Search.create` and `Search.create_async`
2426
- - `language` for full text search
2427
- - `reranker` to reranker search results
2428
-
2429
- ## [0.9.0] - 2024-07-29
2430
- - Added the possibility to make async requests to the unique APIs using either aiohttp or httpx as client
2431
-