unique_toolkit 1.9.1__py3-none-any.whl → 1.11.0__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,9 +1,11 @@
1
1
  import logging
2
+ from typing import Any
2
3
 
4
+ import unique_sdk
3
5
  from openai.types.chat.chat_completion_message_param import ChatCompletionMessageParam
4
6
  from typing_extensions import deprecated
5
7
 
6
- from unique_toolkit.app.schemas import ChatEvent, Event
8
+ from unique_toolkit._common.utils.files import is_file_content, is_image_content
7
9
  from unique_toolkit.chat.constants import (
8
10
  DEFAULT_MAX_MESSAGES,
9
11
  DEFAULT_PERCENT_OF_MAX_TOKENS,
@@ -47,7 +49,16 @@ from unique_toolkit.chat.schemas import (
47
49
  MessageLogStatus,
48
50
  MessageLogUncitedReferences,
49
51
  )
50
- from unique_toolkit.content.schemas import ContentChunk, ContentReference
52
+ from unique_toolkit.content.functions import (
53
+ download_content_to_bytes,
54
+ search_contents,
55
+ upload_content_from_bytes,
56
+ )
57
+ from unique_toolkit.content.schemas import (
58
+ Content,
59
+ ContentChunk,
60
+ ContentReference,
61
+ )
51
62
  from unique_toolkit.language_model.constants import (
52
63
  DEFAULT_COMPLETE_TEMPERATURE,
53
64
  DEFAULT_COMPLETE_TIMEOUT,
@@ -63,6 +74,7 @@ from unique_toolkit.language_model.schemas import (
63
74
  LanguageModelToolDescription,
64
75
  )
65
76
 
77
+ from .deprecated.service import ChatServiceDeprecated
66
78
  from .functions import (
67
79
  stream_complete_with_references,
68
80
  stream_complete_with_references_async,
@@ -71,214 +83,9 @@ from .functions import (
71
83
  logger = logging.getLogger(f"toolkit.{DOMAIN_NAME}.{__name__}")
72
84
 
73
85
 
74
- class ChatService:
86
+ class ChatService(ChatServiceDeprecated):
75
87
  """Provides all functionalities to manage the chat session."""
76
88
 
77
- def __init__(self, event: ChatEvent | Event):
78
- self._event = event
79
- self._company_id: str = event.company_id
80
- self._user_id: str = event.user_id
81
- self._assistant_message_id: str = event.payload.assistant_message.id
82
- self._user_message_id: str = event.payload.user_message.id
83
- self._chat_id: str = event.payload.chat_id
84
- self._assistant_id: str = event.payload.assistant_id
85
- self._user_message_text: str = event.payload.user_message.text
86
-
87
- @property
88
- @deprecated(
89
- "The event property is deprecated and will be removed in a future version.",
90
- )
91
- def event(self) -> Event | ChatEvent:
92
- """Get the event object (deprecated).
93
-
94
- Returns:
95
- Event | BaseEvent | None: The event object.
96
-
97
- """
98
- return self._event
99
-
100
- @property
101
- @deprecated(
102
- "The company_id property is deprecated and will be removed in a future version.",
103
- )
104
- def company_id(self) -> str:
105
- """Get the company identifier (deprecated).
106
-
107
- Returns:
108
- str | None: The company identifier.
109
-
110
- """
111
- return self._company_id
112
-
113
- @company_id.setter
114
- @deprecated(
115
- "The company_id setter is deprecated and will be removed in a future version.",
116
- )
117
- def company_id(self, value: str) -> None:
118
- """Set the company identifier (deprecated).
119
-
120
- Args:
121
- value (str | None): The company identifier.
122
-
123
- """
124
- self._company_id = value
125
-
126
- @property
127
- @deprecated(
128
- "The user_id property is deprecated and will be removed in a future version.",
129
- )
130
- def user_id(self) -> str:
131
- """Get the user identifier (deprecated).
132
-
133
- Returns:
134
- str | None: The user identifier.
135
-
136
- """
137
- return self._user_id
138
-
139
- @user_id.setter
140
- @deprecated(
141
- "The user_id setter is deprecated and will be removed in a future version.",
142
- )
143
- def user_id(self, value: str) -> None:
144
- """Set the user identifier (deprecated).
145
-
146
- Args:
147
- value (str | None): The user identifier.
148
-
149
- """
150
- self._user_id = value
151
-
152
- @property
153
- @deprecated(
154
- "The assistant_message_id property is deprecated and will be removed in a future version.",
155
- )
156
- def assistant_message_id(self) -> str:
157
- """Get the assistant message identifier (deprecated).
158
-
159
- Returns:
160
- str | None: The assistant message identifier.
161
-
162
- """
163
- return self._assistant_message_id
164
-
165
- @assistant_message_id.setter
166
- @deprecated(
167
- "The assistant_message_id setter is deprecated and will be removed in a future version.",
168
- )
169
- def assistant_message_id(self, value: str) -> None:
170
- """Set the assistant message identifier (deprecated).
171
-
172
- Args:
173
- value (str | None): The assistant message identifier.
174
-
175
- """
176
- self._assistant_message_id = value
177
-
178
- @property
179
- @deprecated(
180
- "The user_message_id property is deprecated and will be removed in a future version.",
181
- )
182
- def user_message_id(self) -> str:
183
- """Get the user message identifier (deprecated).
184
-
185
- Returns:
186
- str | None: The user message identifier.
187
-
188
- """
189
- return self._user_message_id
190
-
191
- @user_message_id.setter
192
- @deprecated(
193
- "The user_message_id setter is deprecated and will be removed in a future version.",
194
- )
195
- def user_message_id(self, value: str) -> None:
196
- """Set the user message identifier (deprecated).
197
-
198
- Args:
199
- value (str | None): The user message identifier.
200
-
201
- """
202
- self._user_message_id = value
203
-
204
- @property
205
- @deprecated(
206
- "The chat_id property is deprecated and will be removed in a future version.",
207
- )
208
- def chat_id(self) -> str:
209
- """Get the chat identifier (deprecated).
210
-
211
- Returns:
212
- str | None: The chat identifier.
213
-
214
- """
215
- return self._chat_id
216
-
217
- @chat_id.setter
218
- @deprecated(
219
- "The chat_id setter is deprecated and will be removed in a future version.",
220
- )
221
- def chat_id(self, value: str) -> None:
222
- """Set the chat identifier (deprecated).
223
-
224
- Args:
225
- value (str | None): The chat identifier.
226
-
227
- """
228
- self._chat_id = value
229
-
230
- @property
231
- @deprecated(
232
- "The assistant_id property is deprecated and will be removed in a future version.",
233
- )
234
- def assistant_id(self) -> str:
235
- """Get the assistant identifier (deprecated).
236
-
237
- Returns:
238
- str | None: The assistant identifier.
239
-
240
- """
241
- return self._assistant_id
242
-
243
- @assistant_id.setter
244
- @deprecated(
245
- "The assistant_id setter is deprecated and will be removed in a future version.",
246
- )
247
- def assistant_id(self, value: str) -> None:
248
- """Set the assistant identifier (deprecated).
249
-
250
- Args:
251
- value (str | None): The assistant identifier.
252
-
253
- """
254
- self._assistant_id = value
255
-
256
- @property
257
- @deprecated(
258
- "The user_message_text property is deprecated and will be removed in a future version.",
259
- )
260
- def user_message_text(self) -> str:
261
- """Get the user message text (deprecated).
262
-
263
- Returns:
264
- str | None: The user message text.
265
-
266
- """
267
- return self._user_message_text
268
-
269
- @user_message_text.setter
270
- @deprecated(
271
- "The user_message_text setter is deprecated and will be removed in a future version.",
272
- )
273
- def user_message_text(self, value: str) -> None:
274
- """Set the user message text (deprecated).
275
-
276
- Args:
277
- value (str | None): The user message text.
278
-
279
- """
280
- self._user_message_text = value
281
-
282
89
  async def update_debug_info_async(self, debug_info: dict):
283
90
  """Updates the debug information for the chat session.
284
91
 
@@ -297,25 +104,6 @@ class ChatService:
297
104
  debug_info=debug_info,
298
105
  )
299
106
 
300
- @deprecated("Use `replace_debug_info`")
301
- def update_debug_info(self, debug_info: dict):
302
- """Updates the debug information for the chat session.
303
-
304
- Args:
305
- debug_info (dict): The new debug information.
306
-
307
- """
308
- return modify_message(
309
- user_id=self._user_id,
310
- company_id=self._company_id,
311
- assistant_message_id=self._assistant_message_id,
312
- chat_id=self._chat_id,
313
- user_message_id=self._user_message_id,
314
- user_message_text=self._user_message_text,
315
- assistant=False,
316
- debug_info=debug_info,
317
- )
318
-
319
107
  def replace_debug_info(self, debug_info: dict):
320
108
  """Replace the debug information in the last user message
321
109
 
@@ -334,6 +122,9 @@ class ChatService:
334
122
  debug_info=debug_info,
335
123
  )
336
124
 
125
+ # Message Methods
126
+ ############################################################################
127
+
337
128
  def modify_user_message(
338
129
  self,
339
130
  content: str,
@@ -496,108 +287,6 @@ class ChatService:
496
287
  set_completed_at=set_completed_at or False,
497
288
  )
498
289
 
499
- def free_user_input(self) -> None:
500
- """Unblocks the next user input"""
501
- self.modify_assistant_message(set_completed_at=True)
502
-
503
- def get_full_history(self) -> list[ChatMessage]:
504
- """Loads the full chat history for the chat session synchronously.
505
-
506
- Returns:
507
- list[ChatMessage]: The full chat history.
508
-
509
- Raises:
510
- Exception: If the loading fails.
511
-
512
- """
513
- return get_full_history(
514
- event_user_id=self._user_id,
515
- event_company_id=self._company_id,
516
- event_payload_chat_id=self._chat_id,
517
- )
518
-
519
- async def get_full_history_async(self) -> list[ChatMessage]:
520
- """Loads the full chat history for the chat session asynchronously.
521
-
522
- Returns:
523
- list[ChatMessage]: The full chat history.
524
-
525
- Raises:
526
- Exception: If the loading fails.
527
-
528
- """
529
- return await get_full_history_async(
530
- event_user_id=self._user_id,
531
- event_company_id=self._company_id,
532
- event_payload_chat_id=self._chat_id,
533
- )
534
-
535
- def get_full_and_selected_history(
536
- self,
537
- token_limit: int,
538
- percent_of_max_tokens: float = DEFAULT_PERCENT_OF_MAX_TOKENS,
539
- max_messages: int = DEFAULT_MAX_MESSAGES,
540
- ) -> tuple[list[ChatMessage], list[ChatMessage]]:
541
- """Loads the chat history for the chat session synchronously.
542
-
543
- Args:
544
- token_limit (int): The maximum number of tokens to load.
545
- percent_of_max_tokens (float): The percentage of the maximum tokens to load. Defaults to 0.15.
546
- max_messages (int): The maximum number of messages to load. Defaults to 4.
547
-
548
- Returns:
549
- tuple[list[ChatMessage], list[ChatMessage]]: The selected and full chat history.
550
-
551
- Raises:
552
- Exception: If the loading fails.
553
-
554
- """
555
- full_history = get_full_history(
556
- event_user_id=self._user_id,
557
- event_company_id=self._company_id,
558
- event_payload_chat_id=self._chat_id,
559
- )
560
- selected_history = get_selection_from_history(
561
- full_history=full_history,
562
- max_tokens=int(round(token_limit * percent_of_max_tokens)),
563
- max_messages=max_messages,
564
- )
565
-
566
- return full_history, selected_history
567
-
568
- async def get_full_and_selected_history_async(
569
- self,
570
- token_limit: int,
571
- percent_of_max_tokens: float = DEFAULT_PERCENT_OF_MAX_TOKENS,
572
- max_messages: int = DEFAULT_MAX_MESSAGES,
573
- ) -> tuple[list[ChatMessage], list[ChatMessage]]:
574
- """Loads the chat history for the chat session asynchronously.
575
-
576
- Args:
577
- token_limit (int): The maximum number of tokens to load.
578
- percent_of_max_tokens (float): The percentage of the maximum tokens to load. Defaults to 0.15.
579
- max_messages (int): The maximum number of messages to load. Defaults to 4.
580
-
581
- Returns:
582
- tuple[list[ChatMessage], list[ChatMessage]]: The selected and full chat history.
583
-
584
- Raises:
585
- Exception: If the loading fails.
586
-
587
- """
588
- full_history = await get_full_history_async(
589
- event_user_id=self._user_id,
590
- event_company_id=self._company_id,
591
- event_payload_chat_id=self._chat_id,
592
- )
593
- selected_history = get_selection_from_history(
594
- full_history=full_history,
595
- max_tokens=int(round(token_limit * percent_of_max_tokens)),
596
- max_messages=max_messages,
597
- )
598
-
599
- return full_history, selected_history
600
-
601
290
  def create_assistant_message(
602
291
  self,
603
292
  content: str,
@@ -678,7 +367,6 @@ class ChatService:
678
367
  self._assistant_message_id = chat_message.id or "unknown"
679
368
  return chat_message
680
369
 
681
- @deprecated("Not working at the moment.")
682
370
  def create_user_message(
683
371
  self,
684
372
  content: str,
@@ -759,6 +447,114 @@ class ChatService:
759
447
  self._user_message_id = chat_message.id or "unknown"
760
448
  return chat_message
761
449
 
450
+ def free_user_input(self) -> None:
451
+ """Unblocks the next user input"""
452
+ self.modify_assistant_message(set_completed_at=True)
453
+
454
+ # History Methods
455
+ ############################################################################
456
+
457
+ def get_full_history(self) -> list[ChatMessage]:
458
+ """Loads the full chat history for the chat session synchronously.
459
+
460
+ Returns:
461
+ list[ChatMessage]: The full chat history.
462
+
463
+ Raises:
464
+ Exception: If the loading fails.
465
+
466
+ """
467
+ return get_full_history(
468
+ event_user_id=self._user_id,
469
+ event_company_id=self._company_id,
470
+ event_payload_chat_id=self._chat_id,
471
+ )
472
+
473
+ async def get_full_history_async(self) -> list[ChatMessage]:
474
+ """Loads the full chat history for the chat session asynchronously.
475
+
476
+ Returns:
477
+ list[ChatMessage]: The full chat history.
478
+
479
+ Raises:
480
+ Exception: If the loading fails.
481
+
482
+ """
483
+ return await get_full_history_async(
484
+ event_user_id=self._user_id,
485
+ event_company_id=self._company_id,
486
+ event_payload_chat_id=self._chat_id,
487
+ )
488
+
489
+ def get_full_and_selected_history(
490
+ self,
491
+ token_limit: int,
492
+ percent_of_max_tokens: float = DEFAULT_PERCENT_OF_MAX_TOKENS,
493
+ max_messages: int = DEFAULT_MAX_MESSAGES,
494
+ ) -> tuple[list[ChatMessage], list[ChatMessage]]:
495
+ """Loads the chat history for the chat session synchronously.
496
+
497
+ Args:
498
+ token_limit (int): The maximum number of tokens to load.
499
+ percent_of_max_tokens (float): The percentage of the maximum tokens to load. Defaults to 0.15.
500
+ max_messages (int): The maximum number of messages to load. Defaults to 4.
501
+
502
+ Returns:
503
+ tuple[list[ChatMessage], list[ChatMessage]]: The selected and full chat history.
504
+
505
+ Raises:
506
+ Exception: If the loading fails.
507
+
508
+ """
509
+ full_history = get_full_history(
510
+ event_user_id=self._user_id,
511
+ event_company_id=self._company_id,
512
+ event_payload_chat_id=self._chat_id,
513
+ )
514
+ selected_history = get_selection_from_history(
515
+ full_history=full_history,
516
+ max_tokens=int(round(token_limit * percent_of_max_tokens)),
517
+ max_messages=max_messages,
518
+ )
519
+
520
+ return full_history, selected_history
521
+
522
+ async def get_full_and_selected_history_async(
523
+ self,
524
+ token_limit: int,
525
+ percent_of_max_tokens: float = DEFAULT_PERCENT_OF_MAX_TOKENS,
526
+ max_messages: int = DEFAULT_MAX_MESSAGES,
527
+ ) -> tuple[list[ChatMessage], list[ChatMessage]]:
528
+ """Loads the chat history for the chat session asynchronously.
529
+
530
+ Args:
531
+ token_limit (int): The maximum number of tokens to load.
532
+ percent_of_max_tokens (float): The percentage of the maximum tokens to load. Defaults to 0.15.
533
+ max_messages (int): The maximum number of messages to load. Defaults to 4.
534
+
535
+ Returns:
536
+ tuple[list[ChatMessage], list[ChatMessage]]: The selected and full chat history.
537
+
538
+ Raises:
539
+ Exception: If the loading fails.
540
+
541
+ """
542
+ full_history = await get_full_history_async(
543
+ event_user_id=self._user_id,
544
+ event_company_id=self._company_id,
545
+ event_payload_chat_id=self._chat_id,
546
+ )
547
+ selected_history = get_selection_from_history(
548
+ full_history=full_history,
549
+ max_tokens=int(round(token_limit * percent_of_max_tokens)),
550
+ max_messages=max_messages,
551
+ )
552
+
553
+ return full_history, selected_history
554
+
555
+ # Message Assessment Methods
556
+ ############################################################################
557
+
762
558
  def create_message_assessment(
763
559
  self,
764
560
  assistant_message_id: str,
@@ -913,6 +709,9 @@ class ChatService:
913
709
  label=label,
914
710
  )
915
711
 
712
+ # Message Log Methods
713
+ ############################################################################
714
+
916
715
  def create_message_log(
917
716
  self,
918
717
  message_id: str,
@@ -1149,6 +948,9 @@ class ChatService:
1149
948
  references=references,
1150
949
  )
1151
950
 
951
+ # Message Execution Methods
952
+ ############################################################################
953
+
1152
954
  def create_message_execution(
1153
955
  self,
1154
956
  message_id: str,
@@ -1465,6 +1267,9 @@ class ChatService:
1465
1267
  percentage_completed=percentage_completed,
1466
1268
  )
1467
1269
 
1270
+ # Language Model Methods
1271
+ ############################################################################
1272
+
1468
1273
  @deprecated("Use complete_with_references instead")
1469
1274
  def stream_complete(
1470
1275
  self,
@@ -1628,3 +1433,53 @@ class ChatService:
1628
1433
  )
1629
1434
 
1630
1435
  return LanguageModelResponse.from_stream_response(await response)
1436
+
1437
+ # Chat Content Methods
1438
+ ############################################################################
1439
+
1440
+ def upload_to_chat_from_bytes(
1441
+ self,
1442
+ *,
1443
+ content: bytes,
1444
+ content_name: str,
1445
+ mime_type: str,
1446
+ scope_id: str | None = None,
1447
+ skip_ingestion: bool = False,
1448
+ ingestion_config: unique_sdk.Content.IngestionConfig | None = None,
1449
+ metadata: dict[str, Any] | None = None,
1450
+ ) -> Content:
1451
+ return upload_content_from_bytes(
1452
+ user_id=self._user_id,
1453
+ company_id=self._company_id,
1454
+ content=content,
1455
+ content_name=content_name,
1456
+ mime_type=mime_type,
1457
+ scope_id=scope_id,
1458
+ chat_id=self._chat_id,
1459
+ skip_ingestion=skip_ingestion,
1460
+ ingestion_config=ingestion_config,
1461
+ metadata=metadata,
1462
+ )
1463
+
1464
+ def download_chat_content_to_bytes(self, *, content_id: str) -> bytes:
1465
+ return download_content_to_bytes(
1466
+ user_id=self._user_id,
1467
+ company_id=self._company_id,
1468
+ content_id=content_id,
1469
+ chat_id=self._chat_id,
1470
+ )
1471
+
1472
+ def download_chat_images_and_documents(self) -> tuple[list[Content], list[Content]]:
1473
+ images: list[Content] = []
1474
+ files: list[Content] = []
1475
+ for c in search_contents(
1476
+ user_id=self._user_id,
1477
+ company_id=self._company_id,
1478
+ chat_id=self._chat_id,
1479
+ where={"ownerId": {"equals": self._chat_id}},
1480
+ ):
1481
+ if is_file_content(filename=c.key):
1482
+ files.append(c)
1483
+ if is_image_content(filename=c.key):
1484
+ images.append(c)
1485
+ return images, files
@@ -13,8 +13,10 @@ from unique_toolkit.content.constants import DEFAULT_SEARCH_LANGUAGE
13
13
  from unique_toolkit.content.schemas import (
14
14
  Content,
15
15
  ContentChunk,
16
+ ContentInfo,
16
17
  ContentRerankerConfig,
17
18
  ContentSearchType,
19
+ PaginatedContentInfo,
18
20
  )
19
21
  from unique_toolkit.content.utils import map_contents, map_to_content_chunks
20
22
 
@@ -429,7 +431,7 @@ def _trigger_upload_content(
429
431
  scope_id=scope_id,
430
432
  ) # type: ignore
431
433
 
432
- return Content(**created_content)
434
+ return Content.model_validate(created_content, by_alias=True, by_name=True)
433
435
 
434
436
 
435
437
  def request_content_by_id(
@@ -577,3 +579,59 @@ def download_content(
577
579
  raise Exception(error_msg)
578
580
 
579
581
  return content_path
582
+
583
+
584
+ def get_content_info(
585
+ user_id: str,
586
+ company_id: str,
587
+ metadata_filter: dict[str, Any] | None = None,
588
+ skip: int | None = None,
589
+ take: int | None = None,
590
+ file_path: str | None = None,
591
+ ):
592
+ """Gets the info of a content."""
593
+ get_info_params = unique_sdk.Content.ContentInfoParams(
594
+ metadataFilter=metadata_filter,
595
+ skip=skip,
596
+ take=take,
597
+ filePath=file_path,
598
+ )
599
+
600
+ content_info = unique_sdk.Content.get_info(
601
+ user_id=user_id, company_id=company_id, **get_info_params
602
+ )
603
+ return PaginatedContentInfo.model_validate(
604
+ content_info, by_alias=True, by_name=True
605
+ )
606
+
607
+
608
+ def update_content(
609
+ user_id: str,
610
+ company_id: str,
611
+ *,
612
+ content_id: str,
613
+ metadata: dict[str, Any],
614
+ file_path: str | None = None,
615
+ owner_id: str | None = None,
616
+ parent_folder_path: str | None = None,
617
+ title: str | None = None,
618
+ ) -> ContentInfo:
619
+ """Updates the metadata of a content."""
620
+
621
+ update_params = unique_sdk.Content.UpdateParams(
622
+ contentId=content_id, metadata=metadata
623
+ )
624
+
625
+ if file_path:
626
+ update_params["filePath"] = file_path
627
+ if owner_id:
628
+ update_params["ownerId"] = owner_id
629
+ if parent_folder_path:
630
+ update_params["parentFolderPath"] = parent_folder_path
631
+ if title:
632
+ update_params["title"] = title
633
+
634
+ content_info = unique_sdk.Content.update(
635
+ user_id=user_id, company_id=company_id, **update_params
636
+ )
637
+ return ContentInfo.model_validate(content_info, by_alias=True, by_name=True)
@@ -149,3 +149,26 @@ class ContentRerankerConfig(BaseModel):
149
149
  model_config = model_config
150
150
  deployment_name: str = Field(serialization_alias="deploymentName")
151
151
  options: dict | None = None
152
+
153
+
154
+ class ContentInfo(BaseModel):
155
+ model_config = model_config
156
+ id: str
157
+ key: str
158
+ url: str | None = None
159
+ title: str | None = None
160
+ metadata: dict[str, Any] | None = None
161
+ mime_type: str
162
+ byte_size: int
163
+ owner_id: str
164
+ created_at: datetime
165
+ updated_at: datetime
166
+ expires_at: datetime | None = None
167
+ deleted_at: datetime | None = None
168
+ expired_at: datetime | None = None
169
+
170
+
171
+ class PaginatedContentInfo(BaseModel):
172
+ model_config = model_config
173
+ content_info: list[ContentInfo]
174
+ total_count: int