unique_toolkit 0.5.55__py3-none-any.whl → 0.6.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.
- unique_toolkit/_common/validate_required_values.py +21 -0
- unique_toolkit/app/__init__.py +20 -0
- unique_toolkit/app/schemas.py +73 -7
- unique_toolkit/chat/__init__.py +5 -4
- unique_toolkit/chat/constants.py +3 -0
- unique_toolkit/chat/functions.py +661 -0
- unique_toolkit/chat/schemas.py +11 -11
- unique_toolkit/chat/service.py +273 -430
- unique_toolkit/content/__init__.py +1 -0
- unique_toolkit/content/constants.py +2 -0
- unique_toolkit/content/functions.py +475 -0
- unique_toolkit/content/service.py +163 -315
- unique_toolkit/content/utils.py +32 -0
- unique_toolkit/embedding/__init__.py +3 -0
- unique_toolkit/embedding/constants.py +2 -0
- unique_toolkit/embedding/functions.py +79 -0
- unique_toolkit/embedding/service.py +47 -34
- unique_toolkit/evaluators/__init__.py +1 -0
- unique_toolkit/evaluators/constants.py +1 -0
- unique_toolkit/evaluators/context_relevancy/constants.py +3 -3
- unique_toolkit/evaluators/context_relevancy/utils.py +5 -2
- unique_toolkit/evaluators/hallucination/utils.py +2 -1
- unique_toolkit/language_model/__init__.py +1 -0
- unique_toolkit/language_model/constants.py +4 -0
- unique_toolkit/language_model/functions.py +362 -0
- unique_toolkit/language_model/service.py +246 -293
- unique_toolkit/short_term_memory/__init__.py +5 -0
- unique_toolkit/short_term_memory/constants.py +1 -0
- unique_toolkit/short_term_memory/functions.py +175 -0
- unique_toolkit/short_term_memory/service.py +153 -27
- {unique_toolkit-0.5.55.dist-info → unique_toolkit-0.6.0.dist-info}/METADATA +33 -7
- unique_toolkit-0.6.0.dist-info/RECORD +64 -0
- unique_toolkit-0.5.55.dist-info/RECORD +0 -50
- {unique_toolkit-0.5.55.dist-info → unique_toolkit-0.6.0.dist-info}/LICENSE +0 -0
- {unique_toolkit-0.5.55.dist-info → unique_toolkit-0.6.0.dist-info}/WHEEL +0 -0
unique_toolkit/chat/service.py
CHANGED
@@ -1,39 +1,76 @@
|
|
1
1
|
import logging
|
2
|
-
import re
|
3
2
|
from typing import Optional
|
4
3
|
|
5
|
-
import
|
6
|
-
from unique_sdk._list_object import ListObject
|
4
|
+
from typing_extensions import deprecated
|
7
5
|
|
8
|
-
from unique_toolkit.
|
9
|
-
from unique_toolkit.
|
10
|
-
|
6
|
+
from unique_toolkit.app.schemas import ChatEvent, Event
|
7
|
+
from unique_toolkit.chat.constants import (
|
8
|
+
DEFAULT_MAX_MESSAGES,
|
9
|
+
DEFAULT_PERCENT_OF_MAX_TOKENS,
|
10
|
+
DOMAIN_NAME,
|
11
|
+
)
|
12
|
+
from unique_toolkit.chat.functions import (
|
13
|
+
create_message,
|
14
|
+
create_message_assessment,
|
15
|
+
create_message_assessment_async,
|
16
|
+
create_message_async,
|
17
|
+
get_full_history,
|
18
|
+
get_full_history_async,
|
19
|
+
get_selection_from_history,
|
20
|
+
modify_message,
|
21
|
+
modify_message_assessment,
|
22
|
+
modify_message_assessment_async,
|
23
|
+
modify_message_async,
|
24
|
+
)
|
11
25
|
from unique_toolkit.chat.schemas import (
|
12
26
|
ChatMessage,
|
27
|
+
ChatMessageAssessment,
|
28
|
+
ChatMessageAssessmentLabel,
|
29
|
+
ChatMessageAssessmentStatus,
|
30
|
+
ChatMessageAssessmentType,
|
13
31
|
ChatMessageRole,
|
14
|
-
MessageAssessment,
|
15
|
-
MessageAssessmentLabel,
|
16
|
-
MessageAssessmentStatus,
|
17
|
-
MessageAssessmentType,
|
18
32
|
)
|
19
33
|
from unique_toolkit.content.schemas import ContentReference
|
20
|
-
from unique_toolkit.content.utils import count_tokens
|
21
34
|
|
35
|
+
logger = logging.getLogger(f"toolkit.{DOMAIN_NAME}.{__name__}")
|
22
36
|
|
23
|
-
|
37
|
+
|
38
|
+
class ChatService:
|
24
39
|
"""
|
25
40
|
Provides all functionalities to manage the chat session.
|
26
41
|
|
27
42
|
Attributes:
|
28
|
-
|
29
|
-
|
43
|
+
company_id (str | None): The company ID.
|
44
|
+
user_id (str | None): The user ID.
|
45
|
+
assistant_message_id (str | None): The assistant message ID.
|
46
|
+
user_message_id (str | None): The user message ID.
|
47
|
+
chat_id (str | None): The chat ID.
|
48
|
+
assistant_id (str | None): The assistant ID.
|
49
|
+
user_message_text (str | None): The user message text.
|
30
50
|
"""
|
31
51
|
|
32
|
-
def __init__(self, event:
|
33
|
-
|
52
|
+
def __init__(self, event: ChatEvent | Event):
|
53
|
+
self._event = event
|
54
|
+
self.company_id = event.company_id
|
55
|
+
self.user_id = event.user_id
|
56
|
+
self.assistant_message_id = event.payload.assistant_message.id
|
57
|
+
self.user_message_id = event.payload.user_message.id
|
58
|
+
self.chat_id = event.payload.chat_id
|
59
|
+
self.assistant_id = event.payload.assistant_id
|
60
|
+
self.user_message_text = event.payload.user_message.text
|
34
61
|
|
35
|
-
|
36
|
-
|
62
|
+
@property
|
63
|
+
@deprecated(
|
64
|
+
"The event property is deprecated and will be removed in a future version."
|
65
|
+
)
|
66
|
+
def event(self) -> Event | ChatEvent | None:
|
67
|
+
"""
|
68
|
+
Get the event object (deprecated).
|
69
|
+
|
70
|
+
Returns:
|
71
|
+
Event | BaseEvent | None: The event object.
|
72
|
+
"""
|
73
|
+
return self._event
|
37
74
|
|
38
75
|
async def update_debug_info_async(self, debug_info: dict):
|
39
76
|
"""
|
@@ -42,14 +79,17 @@ class ChatService(BaseService):
|
|
42
79
|
Args:
|
43
80
|
debug_info (dict): The new debug information.
|
44
81
|
"""
|
45
|
-
|
46
|
-
|
82
|
+
|
83
|
+
return await modify_message_async(
|
84
|
+
user_id=self.user_id,
|
85
|
+
company_id=self.company_id,
|
86
|
+
assistant_message_id=self.assistant_message_id,
|
87
|
+
chat_id=self.chat_id,
|
88
|
+
user_message_id=self.user_message_id,
|
89
|
+
user_message_text=self.user_message_text,
|
90
|
+
assistant=False,
|
91
|
+
debug_info=debug_info,
|
47
92
|
)
|
48
|
-
try:
|
49
|
-
await unique_sdk.Message.modify_async(**params)
|
50
|
-
except Exception as e:
|
51
|
-
self.logger.error(f"Failed to update debug info: {e}")
|
52
|
-
raise e
|
53
93
|
|
54
94
|
def update_debug_info(self, debug_info: dict):
|
55
95
|
"""
|
@@ -58,25 +98,28 @@ class ChatService(BaseService):
|
|
58
98
|
Args:
|
59
99
|
debug_info (dict): The new debug information.
|
60
100
|
"""
|
61
|
-
|
62
|
-
|
101
|
+
|
102
|
+
return modify_message(
|
103
|
+
user_id=self.user_id,
|
104
|
+
company_id=self.company_id,
|
105
|
+
assistant_message_id=self.assistant_message_id,
|
106
|
+
chat_id=self.chat_id,
|
107
|
+
user_message_id=self.user_message_id,
|
108
|
+
user_message_text=self.user_message_text,
|
109
|
+
assistant=False,
|
110
|
+
debug_info=debug_info,
|
63
111
|
)
|
64
|
-
try:
|
65
|
-
unique_sdk.Message.modify(**params)
|
66
|
-
except Exception as e:
|
67
|
-
self.logger.error(f"Failed to update debug info: {e}")
|
68
|
-
raise e
|
69
112
|
|
70
113
|
def modify_user_message(
|
71
114
|
self,
|
72
115
|
content: str,
|
73
|
-
references:
|
74
|
-
debug_info:
|
75
|
-
message_id:
|
76
|
-
set_completed_at:
|
116
|
+
references: list[ContentReference] = [],
|
117
|
+
debug_info: dict = {},
|
118
|
+
message_id: str | None = None,
|
119
|
+
set_completed_at: bool | None = False,
|
77
120
|
) -> ChatMessage:
|
78
121
|
"""
|
79
|
-
Modifies a message in the chat session synchronously.
|
122
|
+
Modifies a user message in the chat session synchronously.
|
80
123
|
|
81
124
|
Args:
|
82
125
|
content (str): The new content for the message.
|
@@ -91,28 +134,28 @@ class ChatService(BaseService):
|
|
91
134
|
Raises:
|
92
135
|
Exception: If the modification fails.
|
93
136
|
"""
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
137
|
+
return modify_message(
|
138
|
+
user_id=self.user_id,
|
139
|
+
company_id=self.company_id,
|
140
|
+
assistant_message_id=self.assistant_message_id,
|
141
|
+
chat_id=self.chat_id,
|
142
|
+
user_message_id=self.user_message_id,
|
143
|
+
user_message_text=self.user_message_text,
|
144
|
+
assistant=False,
|
145
|
+
content=content,
|
146
|
+
references=references,
|
147
|
+
debug_info=debug_info,
|
148
|
+
message_id=message_id,
|
149
|
+
set_completed_at=set_completed_at or False,
|
150
|
+
)
|
108
151
|
|
109
152
|
async def modify_user_message_async(
|
110
153
|
self,
|
111
154
|
content: str,
|
112
155
|
references: list[ContentReference] = [],
|
113
156
|
debug_info: dict = {},
|
114
|
-
message_id:
|
115
|
-
set_completed_at:
|
157
|
+
message_id: str | None = None,
|
158
|
+
set_completed_at: bool | None = False,
|
116
159
|
) -> ChatMessage:
|
117
160
|
"""
|
118
161
|
Modifies a message in the chat session asynchronously.
|
@@ -121,8 +164,8 @@ class ChatService(BaseService):
|
|
121
164
|
content (str): The new content for the message.
|
122
165
|
message_id (str, optional): The message ID. Defaults to None, then the ChatState user message id is used.
|
123
166
|
references (list[ContentReference]): list of ContentReference objects. Defaults to None.
|
124
|
-
debug_info (
|
125
|
-
set_completed_at (
|
167
|
+
debug_info (dict[str, Any]]]): Debug information. Defaults to {}.
|
168
|
+
set_completed_at (bool, optional): Whether to set the completedAt field with the current date time. Defaults to False.
|
126
169
|
|
127
170
|
Returns:
|
128
171
|
ChatMessage: The modified message.
|
@@ -130,20 +173,20 @@ class ChatService(BaseService):
|
|
130
173
|
Raises:
|
131
174
|
Exception: If the modification fails.
|
132
175
|
"""
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
176
|
+
return await modify_message_async(
|
177
|
+
user_id=self.user_id,
|
178
|
+
company_id=self.company_id,
|
179
|
+
assistant_message_id=self.assistant_message_id,
|
180
|
+
chat_id=self.chat_id,
|
181
|
+
user_message_id=self.user_message_id,
|
182
|
+
user_message_text=self.user_message_text,
|
183
|
+
assistant=False,
|
184
|
+
content=content,
|
185
|
+
references=references,
|
186
|
+
debug_info=debug_info,
|
187
|
+
message_id=message_id,
|
188
|
+
set_completed_at=set_completed_at or False,
|
189
|
+
)
|
147
190
|
|
148
191
|
def modify_assistant_message(
|
149
192
|
self,
|
@@ -151,8 +194,8 @@ class ChatService(BaseService):
|
|
151
194
|
original_content: str | None = None,
|
152
195
|
references: list[ContentReference] = [],
|
153
196
|
debug_info: dict = {},
|
154
|
-
message_id:
|
155
|
-
set_completed_at:
|
197
|
+
message_id: str | None = None,
|
198
|
+
set_completed_at: bool | None = False,
|
156
199
|
) -> ChatMessage:
|
157
200
|
"""
|
158
201
|
Modifies a message in the chat session synchronously.
|
@@ -171,21 +214,21 @@ class ChatService(BaseService):
|
|
171
214
|
Raises:
|
172
215
|
Exception: If the modification fails.
|
173
216
|
"""
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
217
|
+
return modify_message(
|
218
|
+
user_id=self.user_id,
|
219
|
+
company_id=self.company_id,
|
220
|
+
assistant_message_id=self.assistant_message_id,
|
221
|
+
chat_id=self.chat_id,
|
222
|
+
user_message_id=self.user_message_id,
|
223
|
+
user_message_text=self.user_message_text,
|
224
|
+
assistant=True,
|
225
|
+
content=content,
|
226
|
+
original_content=original_content,
|
227
|
+
references=references,
|
228
|
+
debug_info=debug_info,
|
229
|
+
message_id=message_id,
|
230
|
+
set_completed_at=set_completed_at or False,
|
231
|
+
)
|
189
232
|
|
190
233
|
async def modify_assistant_message_async(
|
191
234
|
self,
|
@@ -193,8 +236,8 @@ class ChatService(BaseService):
|
|
193
236
|
original_content: str | None = None,
|
194
237
|
references: list[ContentReference] = [],
|
195
238
|
debug_info: dict = {},
|
196
|
-
message_id:
|
197
|
-
set_completed_at:
|
239
|
+
message_id: str | None = None,
|
240
|
+
set_completed_at: bool | None = False,
|
198
241
|
) -> ChatMessage:
|
199
242
|
"""
|
200
243
|
Modifies a message in the chat session asynchronously.
|
@@ -204,8 +247,8 @@ class ChatService(BaseService):
|
|
204
247
|
original_content (str, optional): The original content for the message.
|
205
248
|
message_id (str, optional): The message ID. Defaults to None, then the ChatState assistant message id is used.
|
206
249
|
references (list[ContentReference]): list of ContentReference objects. Defaults to None.
|
207
|
-
debug_info (
|
208
|
-
set_completed_at (
|
250
|
+
debug_info (dict[str, Any]], optional): Debug information. Defaults to None.
|
251
|
+
set_completed_at (bool, optional): Whether to set the completedAt field with the current date time. Defaults to False.
|
209
252
|
|
210
253
|
Returns:
|
211
254
|
ChatMessage: The modified message.
|
@@ -213,21 +256,22 @@ class ChatService(BaseService):
|
|
213
256
|
Raises:
|
214
257
|
Exception: If the modification fails.
|
215
258
|
"""
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
259
|
+
|
260
|
+
return await modify_message_async(
|
261
|
+
user_id=self.user_id,
|
262
|
+
company_id=self.company_id,
|
263
|
+
assistant_message_id=self.assistant_message_id,
|
264
|
+
chat_id=self.chat_id,
|
265
|
+
user_message_id=self.user_message_id,
|
266
|
+
user_message_text=self.user_message_text,
|
267
|
+
assistant=True,
|
268
|
+
content=content,
|
269
|
+
original_content=original_content,
|
270
|
+
references=references,
|
271
|
+
debug_info=debug_info,
|
272
|
+
message_id=message_id,
|
273
|
+
set_completed_at=set_completed_at or False,
|
274
|
+
)
|
231
275
|
|
232
276
|
def get_full_history(self) -> list[ChatMessage]:
|
233
277
|
"""
|
@@ -239,7 +283,11 @@ class ChatService(BaseService):
|
|
239
283
|
Raises:
|
240
284
|
Exception: If the loading fails.
|
241
285
|
"""
|
242
|
-
return
|
286
|
+
return get_full_history(
|
287
|
+
event_user_id=self.user_id,
|
288
|
+
event_company_id=self.company_id,
|
289
|
+
event_payload_chat_id=self.chat_id,
|
290
|
+
)
|
243
291
|
|
244
292
|
async def get_full_history_async(self) -> list[ChatMessage]:
|
245
293
|
"""
|
@@ -251,7 +299,11 @@ class ChatService(BaseService):
|
|
251
299
|
Raises:
|
252
300
|
Exception: If the loading fails.
|
253
301
|
"""
|
254
|
-
return await
|
302
|
+
return await get_full_history_async(
|
303
|
+
event_user_id=self.user_id,
|
304
|
+
event_company_id=self.company_id,
|
305
|
+
event_payload_chat_id=self.chat_id,
|
306
|
+
)
|
255
307
|
|
256
308
|
def get_full_and_selected_history(
|
257
309
|
self,
|
@@ -273,8 +325,12 @@ class ChatService(BaseService):
|
|
273
325
|
Raises:
|
274
326
|
Exception: If the loading fails.
|
275
327
|
"""
|
276
|
-
full_history =
|
277
|
-
|
328
|
+
full_history = get_full_history(
|
329
|
+
event_user_id=self.user_id,
|
330
|
+
event_company_id=self.company_id,
|
331
|
+
event_payload_chat_id=self.chat_id,
|
332
|
+
)
|
333
|
+
selected_history = get_selection_from_history(
|
278
334
|
full_history=full_history,
|
279
335
|
max_tokens=int(round(token_limit * percent_of_max_tokens)),
|
280
336
|
max_messages=max_messages,
|
@@ -302,8 +358,12 @@ class ChatService(BaseService):
|
|
302
358
|
Raises:
|
303
359
|
Exception: If the loading fails.
|
304
360
|
"""
|
305
|
-
full_history = await
|
306
|
-
|
361
|
+
full_history = await get_full_history_async(
|
362
|
+
event_user_id=self.user_id,
|
363
|
+
event_company_id=self.company_id,
|
364
|
+
event_payload_chat_id=self.chat_id,
|
365
|
+
)
|
366
|
+
selected_history = get_selection_from_history(
|
307
367
|
full_history=full_history,
|
308
368
|
max_tokens=int(round(token_limit * percent_of_max_tokens)),
|
309
369
|
max_messages=max_messages,
|
@@ -335,23 +395,18 @@ class ChatService(BaseService):
|
|
335
395
|
Raises:
|
336
396
|
Exception: If the creation fails.
|
337
397
|
"""
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
message = unique_sdk.Message.create(**params)
|
351
|
-
except Exception as e:
|
352
|
-
self.logger.error(f"Failed to create assistant message: {e}")
|
353
|
-
raise e
|
354
|
-
return ChatMessage(**message)
|
398
|
+
return create_message(
|
399
|
+
user_id=self.user_id,
|
400
|
+
company_id=self.company_id,
|
401
|
+
chat_id=self.chat_id,
|
402
|
+
assistant_id=self.assistant_id,
|
403
|
+
role=ChatMessageRole.ASSISTANT,
|
404
|
+
content=content,
|
405
|
+
original_content=original_content,
|
406
|
+
references=references,
|
407
|
+
debug_info=debug_info,
|
408
|
+
set_completed_at=set_completed_at,
|
409
|
+
)
|
355
410
|
|
356
411
|
async def create_assistant_message_async(
|
357
412
|
self,
|
@@ -377,233 +432,30 @@ class ChatService(BaseService):
|
|
377
432
|
Raises:
|
378
433
|
Exception: If the creation fails.
|
379
434
|
"""
|
380
|
-
if original_content is None:
|
381
|
-
original_content = content
|
382
|
-
|
383
|
-
try:
|
384
|
-
params = self._construct_message_create_params(
|
385
|
-
content=content,
|
386
|
-
original_content=original_content,
|
387
|
-
references=references,
|
388
|
-
debug_info=debug_info,
|
389
|
-
set_completed_at=set_completed_at,
|
390
|
-
)
|
391
|
-
|
392
|
-
message = await unique_sdk.Message.create_async(**params)
|
393
|
-
except Exception as e:
|
394
|
-
self.logger.error(f"Failed to create assistant message: {e}")
|
395
|
-
raise e
|
396
|
-
return ChatMessage(**message)
|
397
|
-
|
398
|
-
@staticmethod
|
399
|
-
def _map_references(references: list[ContentReference]):
|
400
|
-
return [
|
401
|
-
{
|
402
|
-
"name": ref.name,
|
403
|
-
"url": ref.url,
|
404
|
-
"sequenceNumber": ref.sequence_number,
|
405
|
-
"sourceId": ref.source_id,
|
406
|
-
"source": ref.source,
|
407
|
-
}
|
408
|
-
for ref in references
|
409
|
-
]
|
410
|
-
|
411
|
-
def _get_full_history(self):
|
412
|
-
messages = self._trigger_list_messages(self.event.payload.chat_id)
|
413
|
-
messages = self._filter_valid_messages(messages)
|
414
|
-
|
415
|
-
return self._map_to_chat_messages(messages)
|
416
|
-
|
417
|
-
async def _get_full_history_async(self):
|
418
|
-
messages = await self._trigger_list_messages_async(self.event.payload.chat_id)
|
419
|
-
messages = self._filter_valid_messages(messages)
|
420
|
-
|
421
|
-
return self._map_to_chat_messages(messages)
|
422
|
-
|
423
|
-
@staticmethod
|
424
|
-
def _filter_valid_messages(messages: ListObject[unique_sdk.Message]):
|
425
|
-
SYSTEM_MESSAGE_PREFIX = "[SYSTEM] "
|
426
|
-
|
427
|
-
# Remove the last two messages
|
428
|
-
messages = messages["data"][:-2] # type: ignore
|
429
|
-
filtered_messages = []
|
430
|
-
for message in messages:
|
431
|
-
if message["text"] is None:
|
432
|
-
continue
|
433
|
-
elif SYSTEM_MESSAGE_PREFIX in message["text"]:
|
434
|
-
continue
|
435
|
-
else:
|
436
|
-
filtered_messages.append(message)
|
437
|
-
|
438
|
-
return filtered_messages
|
439
|
-
|
440
|
-
def _trigger_list_messages(self, chat_id: str):
|
441
|
-
try:
|
442
|
-
messages = unique_sdk.Message.list(
|
443
|
-
user_id=self.event.user_id,
|
444
|
-
company_id=self.event.company_id,
|
445
|
-
chatId=chat_id,
|
446
|
-
)
|
447
|
-
return messages
|
448
|
-
except Exception as e:
|
449
|
-
self.logger.error(f"Failed to list chat history: {e}")
|
450
|
-
raise e
|
451
|
-
|
452
|
-
async def _trigger_list_messages_async(self, chat_id: str):
|
453
|
-
try:
|
454
|
-
messages = await unique_sdk.Message.list_async(
|
455
|
-
user_id=self.event.user_id,
|
456
|
-
company_id=self.event.company_id,
|
457
|
-
chatId=chat_id,
|
458
|
-
)
|
459
|
-
return messages
|
460
|
-
except Exception as e:
|
461
|
-
self.logger.error(f"Failed to list chat history: {e}")
|
462
|
-
raise e
|
463
|
-
|
464
|
-
@staticmethod
|
465
|
-
def _map_to_chat_messages(messages: list[dict]):
|
466
|
-
return [ChatMessage(**msg) for msg in messages]
|
467
|
-
|
468
|
-
def _get_selection_from_history(
|
469
|
-
self,
|
470
|
-
full_history: list[ChatMessage],
|
471
|
-
max_tokens: int,
|
472
|
-
max_messages=4,
|
473
|
-
):
|
474
|
-
messages = full_history[-max_messages:]
|
475
|
-
filtered_messages = [m for m in messages if m.content]
|
476
|
-
mapped_messages = []
|
477
|
-
|
478
|
-
for m in filtered_messages:
|
479
|
-
m.content = re.sub(r"<sup>\d+</sup>", "", m.content)
|
480
|
-
m.role = (
|
481
|
-
ChatMessageRole.ASSISTANT
|
482
|
-
if m.role == ChatMessageRole.ASSISTANT
|
483
|
-
else ChatMessageRole.USER
|
484
|
-
)
|
485
|
-
mapped_messages.append(m)
|
486
|
-
|
487
|
-
return self._pick_messages_in_reverse_for_token_window(
|
488
|
-
messages=mapped_messages,
|
489
|
-
limit=max_tokens,
|
490
|
-
)
|
491
435
|
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
f"Limit too low for the initial message. Last message TokenCount {token_count} available tokens {limit} - cutting message in half until it fits"
|
505
|
-
)
|
506
|
-
content = messages[last_index].content
|
507
|
-
messages[last_index].content = content[: len(content) // 2] + "..."
|
508
|
-
token_count = count_tokens(messages[last_index].content)
|
509
|
-
|
510
|
-
while token_count <= limit and last_index > 0:
|
511
|
-
token_count = count_tokens(
|
512
|
-
"".join([msg.content for msg in messages[:last_index]])
|
513
|
-
)
|
514
|
-
if token_count <= limit:
|
515
|
-
last_index -= 1
|
516
|
-
|
517
|
-
last_index = max(0, last_index)
|
518
|
-
return messages[last_index:]
|
519
|
-
|
520
|
-
def _construct_message_modify_params(
|
521
|
-
self,
|
522
|
-
assistant: bool = True,
|
523
|
-
content: Optional[str] = None,
|
524
|
-
original_content: Optional[str] = None,
|
525
|
-
references: Optional[list[ContentReference]] = None,
|
526
|
-
debug_info: Optional[dict] = None,
|
527
|
-
message_id: Optional[str] = None,
|
528
|
-
set_completed_at: Optional[bool] = False,
|
529
|
-
):
|
530
|
-
if message_id:
|
531
|
-
# Message ID specified. No need to guess
|
532
|
-
message_id = message_id
|
533
|
-
elif assistant:
|
534
|
-
# Assistant message ID
|
535
|
-
message_id = self.event.payload.assistant_message.id
|
536
|
-
else:
|
537
|
-
# User message ID
|
538
|
-
message_id = self.event.payload.user_message.id
|
539
|
-
if content is None:
|
540
|
-
content = self.event.payload.user_message.text
|
541
|
-
|
542
|
-
if set_completed_at:
|
543
|
-
completed_at_datetime = _time_utils.get_datetime_now()
|
544
|
-
else:
|
545
|
-
completed_at_datetime = None
|
546
|
-
|
547
|
-
params = {
|
548
|
-
"user_id": self.event.user_id,
|
549
|
-
"company_id": self.event.company_id,
|
550
|
-
"id": message_id,
|
551
|
-
"chatId": self.event.payload.chat_id,
|
552
|
-
"text": content,
|
553
|
-
"originalText": original_content,
|
554
|
-
"references": self._map_references(references) if references else [],
|
555
|
-
"debugInfo": debug_info,
|
556
|
-
"completedAt": completed_at_datetime,
|
557
|
-
}
|
558
|
-
return params
|
559
|
-
|
560
|
-
def _construct_message_create_params(
|
561
|
-
self,
|
562
|
-
role: ChatMessageRole = ChatMessageRole.ASSISTANT,
|
563
|
-
content: Optional[str] = None,
|
564
|
-
original_content: Optional[str] = None,
|
565
|
-
references: Optional[list[ContentReference]] = None,
|
566
|
-
debug_info: Optional[dict] = None,
|
567
|
-
assistantId: Optional[str] = None,
|
568
|
-
set_completed_at: Optional[bool] = False,
|
569
|
-
):
|
570
|
-
if assistantId:
|
571
|
-
# Assistant ID specified. No need to guess
|
572
|
-
assistantId = assistantId
|
573
|
-
else:
|
574
|
-
assistantId = self.event.payload.assistant_id
|
575
|
-
|
576
|
-
if set_completed_at:
|
577
|
-
completed_at_datetime = _time_utils.get_datetime_now()
|
578
|
-
else:
|
579
|
-
completed_at_datetime = None
|
580
|
-
|
581
|
-
if original_content is None:
|
582
|
-
original_content = content
|
583
|
-
|
584
|
-
params = {
|
585
|
-
"user_id": self.event.user_id,
|
586
|
-
"company_id": self.event.company_id,
|
587
|
-
"assistantId": assistantId,
|
588
|
-
"role": role.value.upper(),
|
589
|
-
"chatId": self.event.payload.chat_id,
|
590
|
-
"text": content,
|
591
|
-
"originalText": original_content,
|
592
|
-
"references": self._map_references(references) if references else [],
|
593
|
-
"debugInfo": debug_info,
|
594
|
-
"completedAt": completed_at_datetime,
|
595
|
-
}
|
596
|
-
return params
|
436
|
+
return await create_message_async(
|
437
|
+
user_id=self.user_id,
|
438
|
+
company_id=self.company_id,
|
439
|
+
chat_id=self.chat_id,
|
440
|
+
assistant_id=self.assistant_id,
|
441
|
+
role=ChatMessageRole.ASSISTANT,
|
442
|
+
content=content,
|
443
|
+
original_content=original_content,
|
444
|
+
references=references,
|
445
|
+
debug_info=debug_info,
|
446
|
+
set_completed_at=set_completed_at,
|
447
|
+
)
|
597
448
|
|
598
449
|
def create_message_assessment(
|
599
450
|
self,
|
600
451
|
assistant_message_id: str,
|
601
|
-
status:
|
602
|
-
type:
|
452
|
+
status: ChatMessageAssessmentStatus,
|
453
|
+
type: ChatMessageAssessmentType,
|
454
|
+
title: str | None = None,
|
603
455
|
explanation: str | None = None,
|
604
|
-
label:
|
456
|
+
label: ChatMessageAssessmentLabel | None = None,
|
605
457
|
is_visible: bool = True,
|
606
|
-
) ->
|
458
|
+
) -> ChatMessageAssessment:
|
607
459
|
"""
|
608
460
|
Creates a message assessment for an assistant message synchronously.
|
609
461
|
|
@@ -611,91 +463,88 @@ class ChatService(BaseService):
|
|
611
463
|
assistant_message_id (str): The ID of the assistant message to assess
|
612
464
|
status (MessageAssessmentStatus): The status of the assessment (e.g. "DONE")
|
613
465
|
type (MessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
|
466
|
+
title (str | None): The title of the assessment
|
614
467
|
explanation (str | None): Explanation of the assessment
|
615
|
-
label (MessageAssessmentLabel | None): The assessment label (e.g. "
|
468
|
+
label (MessageAssessmentLabel | None): The assessment label (e.g. "RED")
|
616
469
|
is_visible (bool): Whether the assessment is visible to users. Defaults to True.
|
617
470
|
|
618
471
|
Returns:
|
619
|
-
|
472
|
+
ChatMessageAssessment: The created message assessment
|
620
473
|
|
621
474
|
Raises:
|
622
475
|
Exception: If the creation fails
|
623
476
|
"""
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
return MessageAssessment(**assessment)
|
636
|
-
except Exception as e:
|
637
|
-
self.logger.error(f"Failed to create message assessment: {e}")
|
638
|
-
raise e
|
477
|
+
return create_message_assessment(
|
478
|
+
user_id=self.user_id,
|
479
|
+
company_id=self.company_id,
|
480
|
+
assistant_message_id=assistant_message_id,
|
481
|
+
status=status,
|
482
|
+
type=type,
|
483
|
+
title=title,
|
484
|
+
explanation=explanation,
|
485
|
+
label=label,
|
486
|
+
is_visible=is_visible,
|
487
|
+
)
|
639
488
|
|
640
489
|
async def create_message_assessment_async(
|
641
490
|
self,
|
642
491
|
assistant_message_id: str,
|
643
|
-
status:
|
644
|
-
type:
|
492
|
+
status: ChatMessageAssessmentStatus,
|
493
|
+
type: ChatMessageAssessmentType,
|
494
|
+
title: str | None = None,
|
645
495
|
explanation: str | None = None,
|
646
|
-
label:
|
496
|
+
label: ChatMessageAssessmentLabel | None = None,
|
647
497
|
is_visible: bool = True,
|
648
|
-
) ->
|
498
|
+
) -> ChatMessageAssessment:
|
649
499
|
"""
|
650
500
|
Creates a message assessment for an assistant message asynchronously.
|
651
501
|
|
652
502
|
Args:
|
653
503
|
assistant_message_id (str): The ID of the assistant message to assess
|
654
|
-
status (
|
655
|
-
type (
|
504
|
+
status (ChatMessageAssessmentStatus): The status of the assessment (e.g. "DONE")
|
505
|
+
type (ChatMessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
|
506
|
+
title (str | None): The title of the assessment
|
656
507
|
explanation (str | None): Explanation of the assessment
|
657
|
-
label (
|
508
|
+
label (ChatMessageAssessmentLabel | None): The assessment label (e.g. "RED")
|
658
509
|
is_visible (bool): Whether the assessment is visible to users. Defaults to True.
|
659
510
|
|
660
511
|
Returns:
|
661
|
-
|
512
|
+
ChatMessageAssessment: The created message assessment
|
662
513
|
|
663
514
|
Raises:
|
664
515
|
Exception: If the creation fails
|
665
516
|
"""
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
return MessageAssessment(**assessment)
|
678
|
-
except Exception as e:
|
679
|
-
self.logger.error(f"Failed to create message assessment: {e}")
|
680
|
-
raise e
|
517
|
+
return await create_message_assessment_async(
|
518
|
+
user_id=self.user_id,
|
519
|
+
company_id=self.company_id,
|
520
|
+
assistant_message_id=assistant_message_id,
|
521
|
+
status=status,
|
522
|
+
type=type,
|
523
|
+
title=title,
|
524
|
+
explanation=explanation,
|
525
|
+
label=label,
|
526
|
+
is_visible=is_visible,
|
527
|
+
)
|
681
528
|
|
682
529
|
def modify_message_assessment(
|
683
530
|
self,
|
684
531
|
assistant_message_id: str,
|
685
|
-
status:
|
686
|
-
type:
|
532
|
+
status: ChatMessageAssessmentStatus,
|
533
|
+
type: ChatMessageAssessmentType,
|
534
|
+
title: str | None = None,
|
687
535
|
explanation: str | None = None,
|
688
|
-
label:
|
689
|
-
) ->
|
536
|
+
label: ChatMessageAssessmentLabel | None = None,
|
537
|
+
) -> ChatMessageAssessment:
|
690
538
|
"""
|
691
539
|
Modifies a message assessment for an assistant message synchronously.
|
692
540
|
|
693
541
|
Args:
|
694
542
|
assistant_message_id (str): The ID of the assistant message to assess
|
695
543
|
status (MessageAssessmentStatus): The status of the assessment (e.g. "DONE")
|
544
|
+
title (str | None): The title of the assessment
|
696
545
|
explanation (str | None): Explanation of the assessment
|
697
|
-
label (
|
698
|
-
type (
|
546
|
+
label (ChatMessageAssessmentLabel | None): The assessment label (e.g. "RED")
|
547
|
+
type (ChatMessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
|
699
548
|
|
700
549
|
Returns:
|
701
550
|
dict: The modified message assessment
|
@@ -703,56 +552,50 @@ class ChatService(BaseService):
|
|
703
552
|
Raises:
|
704
553
|
Exception: If the modification fails
|
705
554
|
"""
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
return MessageAssessment(**assessment)
|
717
|
-
except Exception as e:
|
718
|
-
self.logger.error(f"Failed to modify message assessment: {e}")
|
719
|
-
raise e
|
555
|
+
return modify_message_assessment(
|
556
|
+
user_id=self.user_id,
|
557
|
+
company_id=self.company_id,
|
558
|
+
assistant_message_id=assistant_message_id,
|
559
|
+
status=status,
|
560
|
+
type=type,
|
561
|
+
title=title,
|
562
|
+
explanation=explanation,
|
563
|
+
label=label,
|
564
|
+
)
|
720
565
|
|
721
566
|
async def modify_message_assessment_async(
|
722
567
|
self,
|
723
568
|
assistant_message_id: str,
|
724
|
-
type:
|
725
|
-
|
569
|
+
type: ChatMessageAssessmentType,
|
570
|
+
title: str | None = None,
|
571
|
+
status: ChatMessageAssessmentStatus | None = None,
|
726
572
|
explanation: str | None = None,
|
727
|
-
label:
|
728
|
-
) ->
|
573
|
+
label: ChatMessageAssessmentLabel | None = None,
|
574
|
+
) -> ChatMessageAssessment:
|
729
575
|
"""
|
730
576
|
Modifies a message assessment for an assistant message asynchronously.
|
731
577
|
|
732
578
|
Args:
|
733
579
|
assistant_message_id (str): The ID of the assistant message to assess
|
734
|
-
status (
|
580
|
+
status (ChatMessageAssessmentStatus): The status of the assessment (e.g. "DONE")
|
581
|
+
title (str | None): The title of the assessment
|
735
582
|
explanation (str | None): Explanation of the assessment
|
736
|
-
label (
|
737
|
-
type (
|
583
|
+
label (ChatMessageAssessmentLabel | None): The assessment label (e.g. "RED")
|
584
|
+
type (ChatMessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
|
738
585
|
|
739
586
|
Returns:
|
740
|
-
|
587
|
+
ChatMessageAssessment: The modified message assessment
|
741
588
|
|
742
589
|
Raises:
|
743
590
|
Exception: If the modification fails
|
744
591
|
"""
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
return MessageAssessment(**assessment)
|
756
|
-
except Exception as e:
|
757
|
-
self.logger.error(f"Failed to modify message assessment: {e}")
|
758
|
-
raise e
|
592
|
+
return await modify_message_assessment_async(
|
593
|
+
user_id=self.user_id,
|
594
|
+
company_id=self.company_id,
|
595
|
+
assistant_message_id=assistant_message_id,
|
596
|
+
status=status,
|
597
|
+
type=type,
|
598
|
+
title=title,
|
599
|
+
explanation=explanation,
|
600
|
+
label=label,
|
601
|
+
)
|