unique_sdk 0.10.1__py3-none-any.whl → 0.10.2__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.
- unique_sdk/api_resources/_content.py +11 -10
- unique_sdk/utils/chat_in_space.py +116 -2
- {unique_sdk-0.10.1.dist-info → unique_sdk-0.10.2.dist-info}/METADATA +68 -28
- {unique_sdk-0.10.1.dist-info → unique_sdk-0.10.2.dist-info}/RECORD +6 -6
- {unique_sdk-0.10.1.dist-info → unique_sdk-0.10.2.dist-info}/LICENSE +0 -0
- {unique_sdk-0.10.1.dist-info → unique_sdk-0.10.2.dist-info}/WHEEL +0 -0
|
@@ -64,6 +64,7 @@ class Content(APIResource["Content"]):
|
|
|
64
64
|
class SearchParams(RequestOptions):
|
|
65
65
|
where: "Content.ContentWhereInput"
|
|
66
66
|
chatId: NotRequired[str]
|
|
67
|
+
includeFailedContent: NotRequired[bool]
|
|
67
68
|
|
|
68
69
|
class ContentInfoParams(TypedDict):
|
|
69
70
|
"""
|
|
@@ -163,11 +164,11 @@ class Content(APIResource["Content"]):
|
|
|
163
164
|
class MagicTableSheetTable(TypedDict):
|
|
164
165
|
rowId: str
|
|
165
166
|
columns: List["Content.MagicTableSheetTableColumn"]
|
|
166
|
-
|
|
167
|
+
|
|
167
168
|
class MagicTableSheetIngestionConfiguration(TypedDict):
|
|
168
169
|
columnIdsInMetadata: List[str]
|
|
169
170
|
columnIdsInChunkText: List[str]
|
|
170
|
-
|
|
171
|
+
|
|
171
172
|
class MagicTableSheetIngestParams(TypedDict):
|
|
172
173
|
data: List["Content.MagicTableSheetTable"]
|
|
173
174
|
ingestionConfiguration: "Content.MagicTableSheetIngestionConfiguration"
|
|
@@ -298,10 +299,10 @@ class Content(APIResource["Content"]):
|
|
|
298
299
|
|
|
299
300
|
@classmethod
|
|
300
301
|
def ingest_magic_table_sheets(
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
302
|
+
cls,
|
|
303
|
+
user_id: str,
|
|
304
|
+
company_id: str,
|
|
305
|
+
**params: Unpack["Content.MagicTableSheetIngestParams"],
|
|
305
306
|
) -> "Content.MagicTableSheetResponse":
|
|
306
307
|
return cast(
|
|
307
308
|
Content.MagicTableSheetResponse,
|
|
@@ -316,10 +317,10 @@ class Content(APIResource["Content"]):
|
|
|
316
317
|
|
|
317
318
|
@classmethod
|
|
318
319
|
async def ingest_magic_table_sheets_async(
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
320
|
+
cls,
|
|
321
|
+
user_id: str,
|
|
322
|
+
company_id: str,
|
|
323
|
+
**params: Unpack["Content.MagicTableSheetIngestParams"],
|
|
323
324
|
) -> "Content.MagicTableSheetResponse":
|
|
324
325
|
return cast(
|
|
325
326
|
Content.MagicTableSheetResponse,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from typing import List
|
|
3
3
|
|
|
4
|
+
from unique_sdk.api_resources._content import Content
|
|
4
5
|
from unique_sdk.api_resources._space import Space
|
|
6
|
+
from unique_sdk.utils.file_io import upload_file
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
async def send_message_and_wait_for_completion(
|
|
@@ -30,7 +32,6 @@ async def send_message_and_wait_for_completion(
|
|
|
30
32
|
Returns:
|
|
31
33
|
The completed Space.Message.
|
|
32
34
|
"""
|
|
33
|
-
# Send the prompt asynchronously
|
|
34
35
|
response = await Space.create_message_async(
|
|
35
36
|
user_id=user_id,
|
|
36
37
|
company_id=company_id,
|
|
@@ -44,10 +45,123 @@ async def send_message_and_wait_for_completion(
|
|
|
44
45
|
|
|
45
46
|
max_attempts = int(max_wait // poll_interval)
|
|
46
47
|
for _ in range(max_attempts):
|
|
47
|
-
# Poll for the answer
|
|
48
48
|
answer = Space.get_latest_message(user_id, company_id, chat_id)
|
|
49
49
|
if answer.get("stoppedStreamingAt") is not None:
|
|
50
50
|
return answer
|
|
51
51
|
await asyncio.sleep(poll_interval)
|
|
52
52
|
|
|
53
53
|
raise TimeoutError("Timed out waiting for prompt completion.")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
async def chat_against_file(
|
|
57
|
+
user_id: str,
|
|
58
|
+
company_id: str,
|
|
59
|
+
assistant_id: str,
|
|
60
|
+
path_to_file: str,
|
|
61
|
+
displayed_filename: str,
|
|
62
|
+
mime_type: str,
|
|
63
|
+
text: str,
|
|
64
|
+
poll_interval: float = 1.0,
|
|
65
|
+
max_wait: float = 60.0,
|
|
66
|
+
) -> "Space.Message":
|
|
67
|
+
"""
|
|
68
|
+
Chat against a file by uploading it, sending a message and waiting for a reply.
|
|
69
|
+
Args:
|
|
70
|
+
|
|
71
|
+
user_id: The user ID.
|
|
72
|
+
company_id: The company ID.
|
|
73
|
+
assistant_id: The assistant ID.
|
|
74
|
+
path_to_file: Path to the PDF file to upload.
|
|
75
|
+
displayed_filename: Name to display for the uploaded file.
|
|
76
|
+
mime_type: MIME type of the file (e.g., "application/pdf").
|
|
77
|
+
text: Text to send after uploading the file and chat against.
|
|
78
|
+
poll_interval: Seconds between polls for file ingestion.
|
|
79
|
+
max_wait: Maximum seconds to wait for the final response.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
The final message response.
|
|
83
|
+
"""
|
|
84
|
+
chat_id = None
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
response = await send_message_and_wait_for_completion(
|
|
88
|
+
user_id=user_id,
|
|
89
|
+
company_id=company_id,
|
|
90
|
+
assistant_id=assistant_id,
|
|
91
|
+
text="I'm going to upload a file for analysis.",
|
|
92
|
+
)
|
|
93
|
+
chat_id = response.get("chatId")
|
|
94
|
+
|
|
95
|
+
upload_response = upload_file(
|
|
96
|
+
userId=user_id,
|
|
97
|
+
companyId=company_id,
|
|
98
|
+
path_to_file=path_to_file,
|
|
99
|
+
displayed_filename=displayed_filename,
|
|
100
|
+
mime_type=mime_type,
|
|
101
|
+
chat_id=chat_id,
|
|
102
|
+
)
|
|
103
|
+
content_id = upload_response.get("id")
|
|
104
|
+
|
|
105
|
+
await wait_for_ingestion_completion(
|
|
106
|
+
user_id=user_id,
|
|
107
|
+
company_id=company_id,
|
|
108
|
+
content_id=content_id,
|
|
109
|
+
chat_id=chat_id,
|
|
110
|
+
poll_interval=poll_interval,
|
|
111
|
+
max_wait=max_wait,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
final_response = await send_message_and_wait_for_completion(
|
|
115
|
+
user_id=user_id,
|
|
116
|
+
company_id=company_id,
|
|
117
|
+
assistant_id=assistant_id,
|
|
118
|
+
text=text,
|
|
119
|
+
chat_id=chat_id,
|
|
120
|
+
poll_interval=poll_interval,
|
|
121
|
+
max_wait=max_wait,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
return final_response
|
|
125
|
+
|
|
126
|
+
except Exception as err:
|
|
127
|
+
print(f"Error during chat against file: {err}")
|
|
128
|
+
raise
|
|
129
|
+
finally:
|
|
130
|
+
if chat_id:
|
|
131
|
+
Space.delete_chat(
|
|
132
|
+
user_id=user_id,
|
|
133
|
+
company_id=company_id,
|
|
134
|
+
chat_id=chat_id,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
async def wait_for_ingestion_completion(
|
|
139
|
+
user_id: str,
|
|
140
|
+
company_id: str,
|
|
141
|
+
content_id: str,
|
|
142
|
+
chat_id: str,
|
|
143
|
+
poll_interval: float = 1.0,
|
|
144
|
+
max_wait: float = 60.0,
|
|
145
|
+
):
|
|
146
|
+
"""
|
|
147
|
+
Waits until the content ingestionState is FINISHED or the maximum wait time is reached and throws if case of failed status.
|
|
148
|
+
"""
|
|
149
|
+
max_attempts = int(max_wait // poll_interval)
|
|
150
|
+
for _ in range(max_attempts):
|
|
151
|
+
searched_content = Content.search(
|
|
152
|
+
user_id=user_id,
|
|
153
|
+
company_id=company_id,
|
|
154
|
+
where={"id": {"equals": content_id}},
|
|
155
|
+
chatId=chat_id,
|
|
156
|
+
includeFailedContent=True,
|
|
157
|
+
)
|
|
158
|
+
if searched_content:
|
|
159
|
+
ingestion_state = searched_content[0].get("ingestionState")
|
|
160
|
+
if ingestion_state == "FINISHED":
|
|
161
|
+
return
|
|
162
|
+
if isinstance(ingestion_state, str) and ingestion_state.startswith(
|
|
163
|
+
"FAILED"
|
|
164
|
+
):
|
|
165
|
+
raise RuntimeError(f"Ingestion failed with state: {ingestion_state}")
|
|
166
|
+
await asyncio.sleep(poll_interval)
|
|
167
|
+
raise TimeoutError("Timed out waiting for file ingestion to finish.")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: unique_sdk
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.2
|
|
4
4
|
Summary:
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Martin Fadler
|
|
@@ -1024,6 +1024,12 @@ A metadata filter such as the one designed above can be used in a `Search.create
|
|
|
1024
1024
|
|
|
1025
1025
|
## Utils
|
|
1026
1026
|
|
|
1027
|
+
- [Chat History](#chat-history)
|
|
1028
|
+
- [File Io](#file-io)
|
|
1029
|
+
- [Sources](#sources)
|
|
1030
|
+
- [token](#token)
|
|
1031
|
+
- [Chat In Space](#chat-in-space)
|
|
1032
|
+
|
|
1027
1033
|
### Chat History
|
|
1028
1034
|
|
|
1029
1035
|
#### `unique_sdk.utils.chat_history.load_history`
|
|
@@ -1253,33 +1259,64 @@ The script ensures you can flexibly interact with spaces in new or ongoing chats
|
|
|
1253
1259
|
|
|
1254
1260
|
```python
|
|
1255
1261
|
latest_message = await unique_sdk.utils.chat_in_space.send_message_and_wait_for_completion(
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1262
|
+
user_id=user_id,
|
|
1263
|
+
company_id=company_id,
|
|
1264
|
+
assistant_id=assistant_id,
|
|
1265
|
+
text="Tell me a short story.",
|
|
1266
|
+
chat_id=chat_id, # Optional - if no chat id is specified, a new chat will be created
|
|
1267
|
+
tool_choices=["WebSearch"],
|
|
1268
|
+
scope_rules={
|
|
1269
|
+
"or": [
|
|
1270
|
+
{
|
|
1271
|
+
"operator": "in",
|
|
1272
|
+
"path": [
|
|
1273
|
+
"contentId"
|
|
1274
|
+
],
|
|
1275
|
+
"value": [
|
|
1276
|
+
"cont_u888z7cazxxm4lugfdjq7pks"
|
|
1277
|
+
]
|
|
1278
|
+
},
|
|
1279
|
+
{
|
|
1280
|
+
"operator": "contains",
|
|
1281
|
+
"path": [
|
|
1282
|
+
"folderIdPath"
|
|
1283
|
+
],
|
|
1284
|
+
"value": "uniquepathid://scope_btfo28b3eeelwh5obwgea71bl/scope_fn56ta67knd6w4medgq3028fx"
|
|
1285
|
+
}
|
|
1286
|
+
]
|
|
1287
|
+
},
|
|
1288
|
+
)
|
|
1289
|
+
```
|
|
1290
|
+
|
|
1291
|
+
#### `unique_sdk.utils.chat_in_space.chat_against_file`
|
|
1292
|
+
|
|
1293
|
+
The following script enables you to chat against a file.
|
|
1294
|
+
|
|
1295
|
+
You must provide the following parameters:
|
|
1296
|
+
- `assistantId`: The assistant to be used for the chat.
|
|
1297
|
+
- `path_to_file`: The local path of the file to be uploaded.
|
|
1298
|
+
- `displayed_filename`: The name of the file to be displayed.
|
|
1299
|
+
- `mime_type`: The mime type of the ifle to be uploaded.
|
|
1300
|
+
- `text`: The text to be sent to the chat for chatting against the file.
|
|
1301
|
+
|
|
1302
|
+
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.
|
|
1303
|
+
|
|
1304
|
+
**Optional parameters:**
|
|
1305
|
+
- `poll_interval`: The number of seconds to wait between polling attempts (default: `1` second).
|
|
1306
|
+
- `max_wait`: The maximum number of seconds to wait for the message to complete (default: `60` seconds).
|
|
1307
|
+
|
|
1308
|
+
Example of chatting against a PDF. (The usage can be extended to any supported file type)
|
|
1309
|
+
|
|
1310
|
+
```python
|
|
1311
|
+
latest_message = await unique_sdk.utils.chat_in_space.chat_against_file(
|
|
1312
|
+
user_id=user_id,
|
|
1313
|
+
company_id=company_id,
|
|
1314
|
+
assistant_id="assistant_hjcdga64bkcjnhu4",
|
|
1315
|
+
path_to_file="/files/hello.pdf",
|
|
1316
|
+
displayed_filename="hello.pdf"
|
|
1317
|
+
mime_type="application/pdf"
|
|
1318
|
+
text="Give me a bullet point summary of the file.",
|
|
1319
|
+
)
|
|
1283
1320
|
```
|
|
1284
1321
|
|
|
1285
1322
|
## Error Handling
|
|
@@ -1299,6 +1336,9 @@ All notable changes to this project will be documented in this file.
|
|
|
1299
1336
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
1300
1337
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
1301
1338
|
|
|
1339
|
+
## [0.10.2] - 2025-08-05
|
|
1340
|
+
- Add script to chat against file.
|
|
1341
|
+
|
|
1302
1342
|
## [0.10.1] - 2025-08-05
|
|
1303
1343
|
- Allow deletion of a space chat.
|
|
1304
1344
|
|
|
@@ -16,7 +16,7 @@ unique_sdk/_webhook.py,sha256=GYxbUibQN_W4XlNTHaMIksT9FQJk4LJmlKcxOu3jqiU,2855
|
|
|
16
16
|
unique_sdk/api_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
unique_sdk/api_resources/_acronyms.py,sha256=GIU1XH1flGWQYcpsFqTYwg4ioIGxVmb15tux84nmhEg,891
|
|
18
18
|
unique_sdk/api_resources/_chat_completion.py,sha256=ILCAffxkbkfh2iV9L4KKnfe80gZmT9pWfkNmf3mq68U,2172
|
|
19
|
-
unique_sdk/api_resources/_content.py,sha256=
|
|
19
|
+
unique_sdk/api_resources/_content.py,sha256=Rl1Pb0vUQ9EkEQa0XTGOLZamAYlZaz7h6jNWE-zqFaw,9554
|
|
20
20
|
unique_sdk/api_resources/_embedding.py,sha256=C6qak7cCUBMBINfPhgH8taCJZ9n6w1MUElqDJJ8dG10,1281
|
|
21
21
|
unique_sdk/api_resources/_event.py,sha256=bpWF9vstdoAWbUzr-iiGP713ceP0zPk77GJXiImf9zg,374
|
|
22
22
|
unique_sdk/api_resources/_folder.py,sha256=dmPorUoOJSe-hcxlJq3RnkQeZg3gPqGF37ZsLgnloT0,8335
|
|
@@ -29,11 +29,11 @@ unique_sdk/api_resources/_search_string.py,sha256=4Idw6exgZdA8qksz9WkiA68k1hTU-7
|
|
|
29
29
|
unique_sdk/api_resources/_short_term_memory.py,sha256=vPRN-Y0WPx74E6y-A3LocGc0TxJdzT-xGL66WzZwKRg,2820
|
|
30
30
|
unique_sdk/api_resources/_space.py,sha256=9e-_3oBr_25JeRLF7GfaXnIPE33tZ19g0UWxPp_yR4k,4805
|
|
31
31
|
unique_sdk/utils/chat_history.py,sha256=5UqL9hF1O9pV7skbNOlEibF5rHdYsmG3m5-YEPUowOs,3037
|
|
32
|
-
unique_sdk/utils/chat_in_space.py,sha256=
|
|
32
|
+
unique_sdk/utils/chat_in_space.py,sha256=nYmgQYhIxqQex_6zjdCfNuGnjoU14WkxUN6_zmSOiCQ,5169
|
|
33
33
|
unique_sdk/utils/file_io.py,sha256=YY8B7VJcTLOPmCXByiOfNerXGlAtjCC5EVNmAbQJ3dQ,4306
|
|
34
34
|
unique_sdk/utils/sources.py,sha256=wfboE-neMKa0Wuq9QzfAEFMkNLrIrmm0v-QF33sLo6k,4952
|
|
35
35
|
unique_sdk/utils/token.py,sha256=AzKuAA1AwBtnvSFxGcsHLpxXr_wWE5Mj4jYBbOz2ljA,1740
|
|
36
|
-
unique_sdk-0.10.
|
|
37
|
-
unique_sdk-0.10.
|
|
38
|
-
unique_sdk-0.10.
|
|
39
|
-
unique_sdk-0.10.
|
|
36
|
+
unique_sdk-0.10.2.dist-info/LICENSE,sha256=EJCWoHgrXVBUb47PnjeV4MFIEOR71MAdCOIgv61J-4k,1065
|
|
37
|
+
unique_sdk-0.10.2.dist-info/METADATA,sha256=L2sOYupGkEPz5rw9qOtVc5nUtjUBu14pgtC-CpLH9Os,44785
|
|
38
|
+
unique_sdk-0.10.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
39
|
+
unique_sdk-0.10.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|