unique_toolkit 0.8.1__tar.gz → 0.8.3__tar.gz
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-0.8.1 → unique_toolkit-0.8.3}/CHANGELOG.md +10 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/PKG-INFO +11 -1
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/pyproject.toml +1 -1
- unique_toolkit-0.8.3/unique_toolkit/app/dev_util.py +146 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/app/init_sdk.py +32 -1
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/app/schemas.py +9 -0
- unique_toolkit-0.8.3/unique_toolkit/app/unique_settings.py +134 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/chat/service.py +2 -9
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/content/functions.py +5 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/content/service.py +55 -7
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/embedding/service.py +25 -3
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/framework_utilities/langchain/client.py +8 -8
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/framework_utilities/openai/client.py +4 -6
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/language_model/service.py +39 -14
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/short_term_memory/service.py +38 -6
- unique_toolkit-0.8.1/unique_toolkit/app/event_util.py +0 -24
- unique_toolkit-0.8.1/unique_toolkit/app/sse_client.py +0 -20
- unique_toolkit-0.8.1/unique_toolkit/app/unique_settings.py +0 -61
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/LICENSE +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/README.md +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/__init__.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/_common/_base_service.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/_common/_time_utils.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/_common/exception.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/_common/validate_required_values.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/_common/validators.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/app/__init__.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/app/init_logging.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/app/performance/async_tasks.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/app/performance/async_wrapper.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/app/verification.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/chat/__init__.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/chat/constants.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/chat/functions.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/chat/schemas.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/chat/state.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/chat/utils.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/content/__init__.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/content/constants.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/content/schemas.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/content/utils.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/embedding/__init__.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/embedding/constants.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/embedding/functions.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/embedding/schemas.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/embedding/utils.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/__init__.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/config.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/constants.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/context_relevancy/constants.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/context_relevancy/prompts.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/context_relevancy/service.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/context_relevancy/utils.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/exception.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/hallucination/constants.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/hallucination/prompts.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/hallucination/service.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/hallucination/utils.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/output_parser.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/schemas.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/framework_utilities/langchain/history.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/framework_utilities/openai/message_builder.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/framework_utilities/utils.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/language_model/__init__.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/language_model/builder.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/language_model/constants.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/language_model/functions.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/language_model/infos.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/language_model/prompt.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/language_model/reference.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/language_model/schemas.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/language_model/utils.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/protocols/support.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/short_term_memory/__init__.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/short_term_memory/constants.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/short_term_memory/functions.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/short_term_memory/schemas.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/smart_rules/__init__.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/smart_rules/compile.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/tools/tool_definitions.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/tools/tool_definitionsV2.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/tools/tool_factory.py +0 -0
- {unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/tools/tool_progress_reporter.py +0 -0
|
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.8.3] - 2025-08-05
|
|
9
|
+
- Expose threshold field for search.
|
|
10
|
+
|
|
11
|
+
## [0.8.2] - 2025-08-05
|
|
12
|
+
- Implement overloads for services for clearer dev experience
|
|
13
|
+
- Proper typing for SSE event handling
|
|
14
|
+
- Enhanced unique settings. Expose usage of default values in logs
|
|
15
|
+
- SDK Initialization from unique settings
|
|
16
|
+
- Add utilities for to run llm/agent flows for devs
|
|
17
|
+
|
|
8
18
|
## [0.8.1] - 2025-08-05
|
|
9
19
|
- Bump SDK version to support the latest features.
|
|
10
20
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: unique_toolkit
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.3
|
|
4
4
|
Summary:
|
|
5
5
|
License: Proprietary
|
|
6
6
|
Author: Martin Fadler
|
|
@@ -113,6 +113,16 @@ All notable changes to this project will be documented in this file.
|
|
|
113
113
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
114
114
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
115
115
|
|
|
116
|
+
## [0.8.3] - 2025-08-05
|
|
117
|
+
- Expose threshold field for search.
|
|
118
|
+
|
|
119
|
+
## [0.8.2] - 2025-08-05
|
|
120
|
+
- Implement overloads for services for clearer dev experience
|
|
121
|
+
- Proper typing for SSE event handling
|
|
122
|
+
- Enhanced unique settings. Expose usage of default values in logs
|
|
123
|
+
- SDK Initialization from unique settings
|
|
124
|
+
- Add utilities for to run llm/agent flows for devs
|
|
125
|
+
|
|
116
126
|
## [0.8.1] - 2025-08-05
|
|
117
127
|
- Bump SDK version to support the latest features.
|
|
118
128
|
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
from logging import getLogger
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import (
|
|
6
|
+
Awaitable,
|
|
7
|
+
Callable,
|
|
8
|
+
Generator,
|
|
9
|
+
TypeVar,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
from sseclient import SSEClient
|
|
13
|
+
|
|
14
|
+
from unique_toolkit.app import BaseEvent, ChatEvent, EventName
|
|
15
|
+
from unique_toolkit.app.init_sdk import init_unique_sdk
|
|
16
|
+
from unique_toolkit.app.unique_settings import UniqueSettings
|
|
17
|
+
|
|
18
|
+
T = TypeVar("T", bound=BaseEvent)
|
|
19
|
+
|
|
20
|
+
LOGGER = getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_event_name_from_event_class(event_class: type[T]) -> EventName | None:
|
|
24
|
+
if event_class is ChatEvent:
|
|
25
|
+
return EventName.EXTERNAL_MODULE_CHOSEN
|
|
26
|
+
|
|
27
|
+
return None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_sse_client(
|
|
31
|
+
unique_settings: UniqueSettings,
|
|
32
|
+
subscriptions: list[str],
|
|
33
|
+
) -> SSEClient:
|
|
34
|
+
headers = {
|
|
35
|
+
"Authorization": f"Bearer {unique_settings.app.key.get_secret_value()}",
|
|
36
|
+
"x-app-id": unique_settings.app.id.get_secret_value(),
|
|
37
|
+
"x-company-id": unique_settings.auth.company_id.get_secret_value(),
|
|
38
|
+
"x-user-id": unique_settings.auth.user_id.get_secret_value(),
|
|
39
|
+
"x-api-version": unique_settings.api.version,
|
|
40
|
+
}
|
|
41
|
+
return SSEClient(url=unique_settings.api.sse_url(subscriptions), headers=headers)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_event_generator(
|
|
45
|
+
unique_settings: UniqueSettings, event_type: type[T]
|
|
46
|
+
) -> Generator[T, None, None]:
|
|
47
|
+
"""
|
|
48
|
+
Generator that yields only events of the specified type from an SSE stream.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
sse_client: The SSE client to read events from
|
|
52
|
+
event_type: The event class type to filter for
|
|
53
|
+
|
|
54
|
+
Yields:
|
|
55
|
+
Events matching the specified type
|
|
56
|
+
"""
|
|
57
|
+
event_name = get_event_name_from_event_class(event_type)
|
|
58
|
+
if (
|
|
59
|
+
event_name is None
|
|
60
|
+
or not issubclass(event_type, BaseEvent)
|
|
61
|
+
or event_type is BaseEvent
|
|
62
|
+
):
|
|
63
|
+
raise ValueError(f"Event model {event_type} is not a valid event model")
|
|
64
|
+
|
|
65
|
+
subscription = event_name.value
|
|
66
|
+
|
|
67
|
+
for sse_event in get_sse_client(unique_settings, [subscription]):
|
|
68
|
+
try:
|
|
69
|
+
payload = json.loads(sse_event.data)
|
|
70
|
+
parsed_event = event_type.model_validate(payload)
|
|
71
|
+
if parsed_event is None:
|
|
72
|
+
continue
|
|
73
|
+
|
|
74
|
+
yield parsed_event
|
|
75
|
+
|
|
76
|
+
except Exception as e:
|
|
77
|
+
LOGGER.error(f"Could not parse SSE event data as JSON: {e}")
|
|
78
|
+
continue
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def run_demo_with_sse_client(
|
|
82
|
+
unique_settings: UniqueSettings,
|
|
83
|
+
handler: Callable[[BaseEvent], Awaitable[None] | None],
|
|
84
|
+
event_type: type[BaseEvent],
|
|
85
|
+
) -> None:
|
|
86
|
+
"""
|
|
87
|
+
Run a demo with an SSE client using sync handler.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
unique_settings: The unique settings to use for the SSE client
|
|
91
|
+
handler: The sync handler to use for the SSE client
|
|
92
|
+
event_type: The type of event to use for the SSE client
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
event_name = get_event_name_from_event_class(event_type)
|
|
96
|
+
if event_name is None:
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
init_unique_sdk(unique_settings=unique_settings)
|
|
100
|
+
is_async_handler = asyncio.iscoroutinefunction(handler)
|
|
101
|
+
|
|
102
|
+
for event in get_event_generator(unique_settings, event_type):
|
|
103
|
+
if is_async_handler:
|
|
104
|
+
loop = asyncio.get_event_loop()
|
|
105
|
+
loop.run_until_complete(handler(event))
|
|
106
|
+
else:
|
|
107
|
+
handler(event)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def load_event(file_path: Path, event_type: type[BaseEvent]) -> BaseEvent:
|
|
111
|
+
with file_path.open("r") as file:
|
|
112
|
+
event = json.load(file)
|
|
113
|
+
|
|
114
|
+
return event_type.model_validate(event)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def run_demo_with_with_saved_event(
|
|
118
|
+
unique_settings: UniqueSettings,
|
|
119
|
+
handler: Callable[[BaseEvent], Awaitable[None] | None],
|
|
120
|
+
event_type: type[BaseEvent],
|
|
121
|
+
file_path: Path,
|
|
122
|
+
) -> None:
|
|
123
|
+
"""
|
|
124
|
+
Run a demo with an SSE client.
|
|
125
|
+
|
|
126
|
+
Note: event_type is the type of event that the handler expects.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
unique_settings: The unique settings to use for the SSE client
|
|
130
|
+
handler: The handler to use for the SSE client
|
|
131
|
+
event_type: The type of event to use for the SSE client
|
|
132
|
+
"""
|
|
133
|
+
init_unique_sdk(unique_settings=unique_settings)
|
|
134
|
+
|
|
135
|
+
event_name = get_event_name_from_event_class(event_type)
|
|
136
|
+
if event_name is None:
|
|
137
|
+
return
|
|
138
|
+
|
|
139
|
+
event = load_event(file_path, event_type)
|
|
140
|
+
if event is None:
|
|
141
|
+
raise ValueError(f"Event not found in {file_path}")
|
|
142
|
+
|
|
143
|
+
if asyncio.iscoroutinefunction(handler):
|
|
144
|
+
asyncio.run(handler(event))
|
|
145
|
+
else:
|
|
146
|
+
handler(event)
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import overload
|
|
2
4
|
|
|
3
5
|
import unique_sdk
|
|
6
|
+
from typing_extensions import deprecated
|
|
7
|
+
|
|
8
|
+
from unique_toolkit.app.unique_settings import UniqueSettings
|
|
4
9
|
|
|
5
10
|
|
|
6
11
|
def get_env(var_name, default=None, strict=False):
|
|
@@ -24,12 +29,38 @@ def get_env(var_name, default=None, strict=False):
|
|
|
24
29
|
return val or default
|
|
25
30
|
|
|
26
31
|
|
|
27
|
-
|
|
32
|
+
@overload
|
|
33
|
+
def init_unique_sdk(*, env_file: Path | None = None): ...
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@overload
|
|
37
|
+
def init_unique_sdk(*, unique_settings: UniqueSettings): ...
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def init_unique_sdk(
|
|
41
|
+
*, unique_settings: UniqueSettings | None = None, env_file: Path | None = None
|
|
42
|
+
):
|
|
43
|
+
if unique_settings:
|
|
44
|
+
unique_sdk.api_key = unique_settings.app.key.get_secret_value()
|
|
45
|
+
unique_sdk.app_id = unique_settings.app.id.get_secret_value()
|
|
46
|
+
unique_sdk.api_base = unique_settings.api.sdk_url()
|
|
47
|
+
elif env_file:
|
|
48
|
+
unique_settings = UniqueSettings.from_env(env_file=env_file)
|
|
49
|
+
unique_sdk.api_key = unique_settings.app.key.get_secret_value()
|
|
50
|
+
unique_sdk.app_id = unique_settings.app.id.get_secret_value()
|
|
51
|
+
unique_sdk.api_base = unique_settings.api.sdk_url()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@deprecated("Use init_unique_sdk instead")
|
|
55
|
+
def init_sdk(
|
|
56
|
+
strict_all_vars: bool = False,
|
|
57
|
+
):
|
|
28
58
|
"""Initialize the SDK.
|
|
29
59
|
|
|
30
60
|
Args:
|
|
31
61
|
strict_all_vars (bool, optional): This method raises a ValueError if strict and no value is found in the environment. Defaults to False.
|
|
32
62
|
"""
|
|
63
|
+
|
|
33
64
|
unique_sdk.api_key = get_env("API_KEY", default="dummy", strict=strict_all_vars)
|
|
34
65
|
unique_sdk.app_id = get_env("APP_ID", default="dummy", strict=strict_all_vars)
|
|
35
66
|
unique_sdk.api_base = get_env("API_BASE", default=None, strict=strict_all_vars)
|
|
@@ -19,6 +19,15 @@ model_config = ConfigDict(
|
|
|
19
19
|
|
|
20
20
|
class EventName(StrEnum):
|
|
21
21
|
EXTERNAL_MODULE_CHOSEN = "unique.chat.external-module.chosen"
|
|
22
|
+
USER_MESSAGE_CREATED = "unique.chat.user-message.created"
|
|
23
|
+
INGESTION_CONTENT_UPLOADED = "unique.ingestion.content.uploaded"
|
|
24
|
+
INGESTION_CONTENT_FINISHED = "unique.ingestion.content.finished"
|
|
25
|
+
MAGIC_TABLE_IMPORT_COLUMNS = "unique.magic-table.import-columns"
|
|
26
|
+
MAGIC_TABLE_ADD_META_DATA = "unique.magic-table.add-meta-data"
|
|
27
|
+
MAGIC_TABLE_ADD_DOCUMENT = "unique.magic-table.add-document"
|
|
28
|
+
MAGIC_TABLE_DELETE_ROW = "unique.magic-table.delete-row"
|
|
29
|
+
MAGIC_TABLE_DELETE_COLUMN = "unique.magic-table.delete-column"
|
|
30
|
+
MAGIC_TABLE_UPDATE_CELL = "unique.magic-table.update-cell"
|
|
22
31
|
|
|
23
32
|
|
|
24
33
|
class BaseEvent(BaseModel):
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
from logging import getLogger
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Self, TypeVar
|
|
4
|
+
from urllib.parse import urlparse, urlunparse
|
|
5
|
+
|
|
6
|
+
from pydantic import Field, SecretStr, model_validator
|
|
7
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
8
|
+
|
|
9
|
+
logger = getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
T = TypeVar("T", bound=BaseSettings)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def warn_about_defaults(instance: T) -> T:
|
|
15
|
+
"""Log warnings for fields that are using default values."""
|
|
16
|
+
for field_name, model_field in instance.model_fields.items():
|
|
17
|
+
field_value = getattr(instance, field_name)
|
|
18
|
+
if field_value == model_field.default:
|
|
19
|
+
logger.warning(
|
|
20
|
+
f"Using default value for '{field_name}': {model_field.default}"
|
|
21
|
+
)
|
|
22
|
+
return instance
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class UniqueApp(BaseSettings):
|
|
26
|
+
id: SecretStr = Field(default=SecretStr("dummy_id"))
|
|
27
|
+
key: SecretStr = Field(default=SecretStr("dummy_key"))
|
|
28
|
+
base_url: str = Field(
|
|
29
|
+
default="http://localhost:8092/",
|
|
30
|
+
deprecated="Use UniqueApi.base_url instead",
|
|
31
|
+
)
|
|
32
|
+
endpoint: str = Field(default="dummy")
|
|
33
|
+
endpoint_secret: SecretStr = Field(default=SecretStr("dummy_secret"))
|
|
34
|
+
|
|
35
|
+
@model_validator(mode="after")
|
|
36
|
+
def _warn_about_defaults(self) -> Self:
|
|
37
|
+
return warn_about_defaults(self)
|
|
38
|
+
|
|
39
|
+
model_config = SettingsConfigDict(
|
|
40
|
+
env_prefix="unique_app_",
|
|
41
|
+
env_file_encoding="utf-8",
|
|
42
|
+
case_sensitive=False,
|
|
43
|
+
extra="ignore",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class UniqueApi(BaseSettings):
|
|
48
|
+
base_url: str = Field(
|
|
49
|
+
default="http://localhost:8092/",
|
|
50
|
+
description="The base URL of the Unique API. Ask your admin to provide you with the correct URL.",
|
|
51
|
+
)
|
|
52
|
+
version: str = Field(default="2023-12-06")
|
|
53
|
+
|
|
54
|
+
model_config = SettingsConfigDict(
|
|
55
|
+
env_prefix="unique_api_",
|
|
56
|
+
env_file_encoding="utf-8",
|
|
57
|
+
case_sensitive=False,
|
|
58
|
+
extra="ignore",
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
@model_validator(mode="after")
|
|
62
|
+
def _warn_about_defaults(self) -> Self:
|
|
63
|
+
return warn_about_defaults(self)
|
|
64
|
+
|
|
65
|
+
def sse_url(self, subscriptions: list[str]) -> str:
|
|
66
|
+
parsed = urlparse(self.base_url)
|
|
67
|
+
return urlunparse(
|
|
68
|
+
parsed._replace(
|
|
69
|
+
path="/public/event-socket/events/stream",
|
|
70
|
+
query=f"subscriptions={','.join(subscriptions)}",
|
|
71
|
+
fragment=None,
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
def sdk_url(self) -> str:
|
|
76
|
+
parsed = urlparse(self.base_url)
|
|
77
|
+
|
|
78
|
+
path = "/public/chat"
|
|
79
|
+
if parsed.hostname and "qa.unique" in parsed.hostname:
|
|
80
|
+
path = "/public/chat-gen2"
|
|
81
|
+
return urlunparse(parsed._replace(path=path, query=None, fragment=None))
|
|
82
|
+
|
|
83
|
+
def openai_proxy_url(self) -> str:
|
|
84
|
+
parsed = urlparse(self.base_url)
|
|
85
|
+
return urlunparse(
|
|
86
|
+
parsed._replace(path="/public/openai-proxy/", query=None, fragment=None)
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class UniqueAuth(BaseSettings):
|
|
91
|
+
company_id: SecretStr = Field(default=SecretStr("dummy_company_id"))
|
|
92
|
+
user_id: SecretStr = Field(default=SecretStr("dummy_user_id"))
|
|
93
|
+
|
|
94
|
+
model_config = SettingsConfigDict(
|
|
95
|
+
env_prefix="unique_auth_",
|
|
96
|
+
env_file_encoding="utf-8",
|
|
97
|
+
case_sensitive=False,
|
|
98
|
+
extra="ignore",
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
@model_validator(mode="after")
|
|
102
|
+
def _warn_about_defaults(self) -> Self:
|
|
103
|
+
return warn_about_defaults(self)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class UniqueSettings:
|
|
107
|
+
def __init__(self, auth: UniqueAuth, app: UniqueApp, api: UniqueApi):
|
|
108
|
+
self.app = app
|
|
109
|
+
self.auth = auth
|
|
110
|
+
self.api = api
|
|
111
|
+
|
|
112
|
+
@classmethod
|
|
113
|
+
def from_env(cls, env_file: Path | None = None) -> "UniqueSettings":
|
|
114
|
+
"""Initialize settings from environment variables and/or env file.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
env_file: Optional path to environment file. If provided, will load variables from this file.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
UniqueSettings instance with values loaded from environment/env file.
|
|
121
|
+
|
|
122
|
+
Raises:
|
|
123
|
+
FileNotFoundError: If env_file is provided but does not exist.
|
|
124
|
+
ValidationError: If required environment variables are missing.
|
|
125
|
+
"""
|
|
126
|
+
if env_file and not env_file.exists():
|
|
127
|
+
raise FileNotFoundError(f"Environment file not found: {env_file}")
|
|
128
|
+
|
|
129
|
+
# Initialize settings with environment file if provided
|
|
130
|
+
env_file_str = str(env_file) if env_file else None
|
|
131
|
+
auth = UniqueAuth(_env_file=env_file_str)
|
|
132
|
+
app = UniqueApp(_env_file=env_file_str)
|
|
133
|
+
api = UniqueApi(_env_file=env_file_str)
|
|
134
|
+
return cls(auth=auth, app=app, api=api)
|
|
@@ -57,15 +57,6 @@ logger = logging.getLogger(f"toolkit.{DOMAIN_NAME}.{__name__}")
|
|
|
57
57
|
class ChatService:
|
|
58
58
|
"""
|
|
59
59
|
Provides all functionalities to manage the chat session.
|
|
60
|
-
|
|
61
|
-
Attributes:
|
|
62
|
-
company_id (str | None): The company ID.
|
|
63
|
-
user_id (str | None): The user ID.
|
|
64
|
-
assistant_message_id (str | None): The assistant message ID.
|
|
65
|
-
user_message_id (str | None): The user message ID.
|
|
66
|
-
chat_id (str | None): The chat ID.
|
|
67
|
-
assistant_id (str | None): The assistant ID.
|
|
68
|
-
user_message_text (str | None): The user message text.
|
|
69
60
|
"""
|
|
70
61
|
|
|
71
62
|
def __init__(self, event: ChatEvent | Event):
|
|
@@ -88,6 +79,7 @@ class ChatService:
|
|
|
88
79
|
|
|
89
80
|
Returns:
|
|
90
81
|
Event | BaseEvent | None: The event object.
|
|
82
|
+
|
|
91
83
|
"""
|
|
92
84
|
return self._event
|
|
93
85
|
|
|
@@ -101,6 +93,7 @@ class ChatService:
|
|
|
101
93
|
|
|
102
94
|
Returns:
|
|
103
95
|
str | None: The company identifier.
|
|
96
|
+
|
|
104
97
|
"""
|
|
105
98
|
return self._company_id
|
|
106
99
|
|
|
@@ -34,6 +34,7 @@ def search_content_chunks(
|
|
|
34
34
|
chat_only: bool | None = None,
|
|
35
35
|
metadata_filter: dict | None = None,
|
|
36
36
|
content_ids: list[str] | None = None,
|
|
37
|
+
score_threshold: float | None = None,
|
|
37
38
|
) -> list[ContentChunk]:
|
|
38
39
|
"""
|
|
39
40
|
Performs a synchronous search for content chunks in the knowledge base.
|
|
@@ -48,6 +49,7 @@ def search_content_chunks(
|
|
|
48
49
|
chat_only (bool | None): Whether to search only in the current chat. Defaults to None.
|
|
49
50
|
metadata_filter (dict | None): UniqueQL metadata filter. If unspecified/None, it tries to use the metadata filter from the event. Defaults to None.
|
|
50
51
|
content_ids (list[str] | None): The content IDs to search. Defaults to None.
|
|
52
|
+
score_threshold (float | None): The minimum score threshold for results. Defaults to 0.
|
|
51
53
|
Returns:
|
|
52
54
|
list[ContentChunk]: The search results.
|
|
53
55
|
"""
|
|
@@ -73,6 +75,7 @@ def search_content_chunks(
|
|
|
73
75
|
chatOnly=chat_only,
|
|
74
76
|
metaDataFilter=metadata_filter,
|
|
75
77
|
contentIds=content_ids,
|
|
78
|
+
scoreThreshold=score_threshold,
|
|
76
79
|
)
|
|
77
80
|
return map_to_content_chunks(searches)
|
|
78
81
|
except Exception as e:
|
|
@@ -93,6 +96,7 @@ async def search_content_chunks_async(
|
|
|
93
96
|
chat_only: bool | None = None,
|
|
94
97
|
metadata_filter: dict | None = None,
|
|
95
98
|
content_ids: list[str] | None = None,
|
|
99
|
+
score_threshold: float | None = None,
|
|
96
100
|
):
|
|
97
101
|
"""
|
|
98
102
|
Performs an asynchronous search for content chunks in the knowledge base.
|
|
@@ -121,6 +125,7 @@ async def search_content_chunks_async(
|
|
|
121
125
|
chatOnly=chat_only,
|
|
122
126
|
metaDataFilter=metadata_filter,
|
|
123
127
|
contentIds=content_ids,
|
|
128
|
+
scoreThreshold=score_threshold,
|
|
124
129
|
)
|
|
125
130
|
return map_to_content_chunks(searches)
|
|
126
131
|
except Exception as e:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any, overload
|
|
4
4
|
|
|
5
5
|
import unique_sdk
|
|
6
6
|
from requests import Response
|
|
@@ -35,13 +35,30 @@ logger = logging.getLogger(f"toolkit.{DOMAIN_NAME}.{__name__}")
|
|
|
35
35
|
class ContentService:
|
|
36
36
|
"""
|
|
37
37
|
Provides methods for searching, downloading and uploading content in the knowledge base.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
@deprecated(
|
|
41
|
+
"Use __init__ with company_id, user_id and chat_id instead or use the classmethod `from_event`"
|
|
42
|
+
)
|
|
43
|
+
@overload
|
|
44
|
+
def __init__(self, event: Event | ChatEvent | BaseEvent): ...
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
Initialize the ContentService with an event (deprecated)
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
@overload
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
*,
|
|
54
|
+
company_id: str,
|
|
55
|
+
user_id: str,
|
|
56
|
+
chat_id: str | None,
|
|
57
|
+
metadata_filter: dict | None = None,
|
|
58
|
+
): ...
|
|
38
59
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
company_id (str): The company ID.
|
|
42
|
-
user_id (str): The user ID.
|
|
43
|
-
chat_id (str): The chat ID. Defaults to None
|
|
44
|
-
metadata_filter (dict | None): is only initialised from an Event(Deprecated) or ChatEvent.
|
|
60
|
+
"""
|
|
61
|
+
Initialize the ContentService with a company_id, user_id and chat_id and metadata_filter.
|
|
45
62
|
"""
|
|
46
63
|
|
|
47
64
|
def __init__(
|
|
@@ -50,7 +67,12 @@ class ContentService:
|
|
|
50
67
|
company_id: str | None = None,
|
|
51
68
|
user_id: str | None = None,
|
|
52
69
|
chat_id: str | None = None,
|
|
70
|
+
metadata_filter: dict | None = None,
|
|
53
71
|
):
|
|
72
|
+
"""
|
|
73
|
+
Initialize the ContentService with a company_id, user_id and chat_id.
|
|
74
|
+
"""
|
|
75
|
+
|
|
54
76
|
self._event = event # Changed to protected attribute
|
|
55
77
|
self._metadata_filter = None
|
|
56
78
|
if event:
|
|
@@ -64,6 +86,26 @@ class ContentService:
|
|
|
64
86
|
self._company_id: str = company_id
|
|
65
87
|
self._user_id: str = user_id
|
|
66
88
|
self._chat_id: str | None = chat_id
|
|
89
|
+
self._metadata_filter = metadata_filter
|
|
90
|
+
|
|
91
|
+
@classmethod
|
|
92
|
+
def from_event(cls, event: Event | ChatEvent | BaseEvent):
|
|
93
|
+
"""
|
|
94
|
+
Initialize the ContentService with an event.
|
|
95
|
+
"""
|
|
96
|
+
chat_id = None
|
|
97
|
+
metadata_filter = None
|
|
98
|
+
|
|
99
|
+
if isinstance(event, (ChatEvent | Event)):
|
|
100
|
+
chat_id = event.payload.chat_id
|
|
101
|
+
metadata_filter = event.payload.metadata_filter
|
|
102
|
+
|
|
103
|
+
return cls(
|
|
104
|
+
company_id=event.company_id,
|
|
105
|
+
user_id=event.user_id,
|
|
106
|
+
chat_id=chat_id,
|
|
107
|
+
metadata_filter=metadata_filter,
|
|
108
|
+
)
|
|
67
109
|
|
|
68
110
|
@property
|
|
69
111
|
@deprecated(
|
|
@@ -194,6 +236,7 @@ class ContentService:
|
|
|
194
236
|
chat_only: bool | None = None,
|
|
195
237
|
metadata_filter: dict | None = None,
|
|
196
238
|
content_ids: list[str] | None = None,
|
|
239
|
+
score_threshold: float | None = None,
|
|
197
240
|
) -> list[ContentChunk]:
|
|
198
241
|
"""
|
|
199
242
|
Performs a synchronous search for content chunks in the knowledge base.
|
|
@@ -209,6 +252,7 @@ class ContentService:
|
|
|
209
252
|
chat_only (bool | None, optional): Whether to search only in the current chat. Defaults to None.
|
|
210
253
|
metadata_filter (dict | None, optional): UniqueQL metadata filter. If unspecified/None, it tries to use the metadata filter from the event. Defaults to None.
|
|
211
254
|
content_ids (list[str] | None, optional): The content IDs to search within. Defaults to None.
|
|
255
|
+
score_threshold (float | None, optional): Sets the minimum similarity score for search results to be considered. Defaults to 0.
|
|
212
256
|
|
|
213
257
|
Returns:
|
|
214
258
|
list[ContentChunk]: The search results.
|
|
@@ -239,6 +283,7 @@ class ContentService:
|
|
|
239
283
|
chat_only=chat_only,
|
|
240
284
|
metadata_filter=metadata_filter,
|
|
241
285
|
content_ids=content_ids,
|
|
286
|
+
score_threshold=score_threshold,
|
|
242
287
|
)
|
|
243
288
|
return searches
|
|
244
289
|
except Exception as e:
|
|
@@ -257,6 +302,7 @@ class ContentService:
|
|
|
257
302
|
chat_only: bool | None = None,
|
|
258
303
|
metadata_filter: dict | None = None,
|
|
259
304
|
content_ids: list[str] | None = None,
|
|
305
|
+
score_threshold: float | None = None,
|
|
260
306
|
):
|
|
261
307
|
"""
|
|
262
308
|
Performs an asynchronous search for content chunks in the knowledge base.
|
|
@@ -272,6 +318,7 @@ class ContentService:
|
|
|
272
318
|
chat_only (bool | None, optional): Whether to search only in the current chat. Defaults to None.
|
|
273
319
|
metadata_filter (dict | None, optional): UniqueQL metadata filter. If unspecified/None, it tries to use the metadata filter from the event. Defaults to None.
|
|
274
320
|
content_ids (list[str] | None, optional): The content IDs to search within. Defaults to None.
|
|
321
|
+
score_threshold (float | None, optional): Sets the minimum similarity score for search results to be considered. Defaults to 0.
|
|
275
322
|
|
|
276
323
|
Returns:
|
|
277
324
|
list[ContentChunk]: The search results.
|
|
@@ -301,6 +348,7 @@ class ContentService:
|
|
|
301
348
|
chat_only=chat_only,
|
|
302
349
|
metadata_filter=metadata_filter,
|
|
303
350
|
content_ids=content_ids,
|
|
351
|
+
score_threshold=score_threshold,
|
|
304
352
|
)
|
|
305
353
|
return searches
|
|
306
354
|
except Exception as e:
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from typing import overload
|
|
2
|
+
|
|
1
3
|
from typing_extensions import deprecated
|
|
2
4
|
|
|
3
5
|
from unique_toolkit._common._base_service import BaseService
|
|
@@ -11,10 +13,23 @@ from unique_toolkit.embedding.schemas import Embeddings
|
|
|
11
13
|
class EmbeddingService(BaseService):
|
|
12
14
|
"""
|
|
13
15
|
Provides methods to interact with the Embedding service.
|
|
16
|
+
"""
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
company_id
|
|
17
|
-
|
|
18
|
+
@deprecated(
|
|
19
|
+
"Use __init__ with company_id and user_id instead or use the classmethod `from_event`"
|
|
20
|
+
)
|
|
21
|
+
@overload
|
|
22
|
+
def __init__(self, event: Event | BaseEvent): ...
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
Initialize the EmbeddingService with an event (deprecated)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
@overload
|
|
29
|
+
def __init__(self, *, company_id: str, user_id: str): ...
|
|
30
|
+
|
|
31
|
+
"""
|
|
32
|
+
Initialize the EmbeddingService with a company_id and user_id.
|
|
18
33
|
"""
|
|
19
34
|
|
|
20
35
|
def __init__(
|
|
@@ -32,6 +47,13 @@ class EmbeddingService(BaseService):
|
|
|
32
47
|
self._company_id: str = company_id
|
|
33
48
|
self._user_id: str = user_id
|
|
34
49
|
|
|
50
|
+
@classmethod
|
|
51
|
+
def from_event(cls, event: Event | BaseEvent):
|
|
52
|
+
"""
|
|
53
|
+
Initialize the EmbeddingService with an event.
|
|
54
|
+
"""
|
|
55
|
+
return cls(company_id=event.company_id, user_id=event.user_id)
|
|
56
|
+
|
|
35
57
|
@property
|
|
36
58
|
@deprecated(
|
|
37
59
|
"The event property is deprecated and will be removed in a future version."
|
{unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/framework_utilities/langchain/client.py
RENAMED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import importlib.util
|
|
2
2
|
import logging
|
|
3
|
-
from pathlib import Path
|
|
4
3
|
|
|
5
4
|
from unique_toolkit.app.unique_settings import UniqueSettings
|
|
6
5
|
from unique_toolkit.framework_utilities.utils import get_default_headers
|
|
@@ -23,11 +22,13 @@ else:
|
|
|
23
22
|
raise LangchainNotInstalledError()
|
|
24
23
|
|
|
25
24
|
|
|
26
|
-
def get_client(
|
|
25
|
+
def get_client(
|
|
26
|
+
unique_settings: UniqueSettings, model: str = "AZURE_GPT_4o_2024_0806"
|
|
27
|
+
) -> ChatOpenAI:
|
|
27
28
|
"""Get a Langchain ChatOpenAI client instance.
|
|
28
29
|
|
|
29
30
|
Args:
|
|
30
|
-
|
|
31
|
+
unique_settings: UniqueSettings instance
|
|
31
32
|
|
|
32
33
|
Returns:
|
|
33
34
|
ChatOpenAI client instance
|
|
@@ -35,11 +36,10 @@ def get_client(env_file: Path | None = None) -> ChatOpenAI:
|
|
|
35
36
|
Raises:
|
|
36
37
|
LangchainNotInstalledError: If langchain-openai package is not installed
|
|
37
38
|
"""
|
|
38
|
-
settings = UniqueSettings.from_env(env_file=env_file)
|
|
39
39
|
|
|
40
40
|
return ChatOpenAI(
|
|
41
|
-
base_url=
|
|
42
|
-
default_headers=get_default_headers(
|
|
43
|
-
model=
|
|
44
|
-
api_key=
|
|
41
|
+
base_url=unique_settings.api.openai_proxy_url(),
|
|
42
|
+
default_headers=get_default_headers(unique_settings.app, unique_settings.auth),
|
|
43
|
+
model=model,
|
|
44
|
+
api_key=unique_settings.app.key,
|
|
45
45
|
)
|
{unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/framework_utilities/openai/client.py
RENAMED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import importlib.util
|
|
2
2
|
import logging
|
|
3
|
-
from pathlib import Path
|
|
4
3
|
|
|
5
4
|
from unique_toolkit.app.unique_settings import UniqueSettings
|
|
6
5
|
from unique_toolkit.framework_utilities.utils import get_default_headers
|
|
@@ -23,7 +22,7 @@ else:
|
|
|
23
22
|
raise OpenAINotInstalledError()
|
|
24
23
|
|
|
25
24
|
|
|
26
|
-
def get_openai_client(
|
|
25
|
+
def get_openai_client(unique_settings: UniqueSettings) -> OpenAI:
|
|
27
26
|
"""Get an OpenAI client instance.
|
|
28
27
|
|
|
29
28
|
Args:
|
|
@@ -35,11 +34,10 @@ def get_openai_client(env_file: Path | None = None) -> OpenAI:
|
|
|
35
34
|
Raises:
|
|
36
35
|
OpenAINotInstalledError: If OpenAI package is not installed
|
|
37
36
|
"""
|
|
38
|
-
|
|
39
|
-
default_headers = get_default_headers(settings.app, settings.auth)
|
|
37
|
+
default_headers = get_default_headers(unique_settings.app, unique_settings.auth)
|
|
40
38
|
|
|
41
39
|
return OpenAI(
|
|
42
|
-
api_key=
|
|
43
|
-
base_url=
|
|
40
|
+
api_key=unique_settings.app.key.get_secret_value(),
|
|
41
|
+
base_url=unique_settings.api.openai_proxy_url(),
|
|
44
42
|
default_headers=default_headers,
|
|
45
43
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Any, Optional, Type
|
|
2
|
+
from typing import Any, Optional, Type, overload
|
|
3
3
|
|
|
4
4
|
from pydantic import BaseModel
|
|
5
5
|
from typing_extensions import deprecated
|
|
@@ -33,36 +33,61 @@ logger = logging.getLogger(f"toolkit.{DOMAIN_NAME}.{__name__}")
|
|
|
33
33
|
class LanguageModelService:
|
|
34
34
|
"""
|
|
35
35
|
Provides methods to interact with the Language Model by generating responses.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
@deprecated(
|
|
39
|
+
"Use __init__ with company_id and user_id instead or use the classmethod `from_event`"
|
|
40
|
+
)
|
|
41
|
+
@overload
|
|
42
|
+
def __init__(self, event: Event | ChatEvent | BaseEvent): ...
|
|
43
|
+
|
|
44
|
+
"""
|
|
45
|
+
Initialize the LanguageModelService with an event (deprecated)
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
@overload
|
|
49
|
+
def __init__(self, *, company_id: str, user_id: str): ...
|
|
36
50
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
user_id (str | None, optional): The user identifier. Defaults to None.
|
|
40
|
-
chat_id (str | None, optional): The chat identifier. Defaults to None.
|
|
41
|
-
assistant_id (str | None, optional): The assistant identifier. Defaults to None.
|
|
51
|
+
"""
|
|
52
|
+
Initialize the LanguageModelService with a company_id and user_id.
|
|
42
53
|
"""
|
|
43
54
|
|
|
44
55
|
def __init__(
|
|
45
56
|
self,
|
|
46
|
-
event: Event | BaseEvent | None = None,
|
|
57
|
+
event: Event | ChatEvent | BaseEvent | None = None,
|
|
47
58
|
company_id: str | None = None,
|
|
48
59
|
user_id: str | None = None,
|
|
49
|
-
|
|
50
|
-
assistant_id: str | None = None,
|
|
60
|
+
**kwargs: dict[str, Any], # only here for backward compatibility
|
|
51
61
|
):
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if event:
|
|
62
|
+
if isinstance(event, (ChatEvent, Event)):
|
|
63
|
+
self._event = event
|
|
64
|
+
self._chat_id: str | None = event.payload.chat_id
|
|
65
|
+
self._assistant_id: str | None = event.payload.assistant_id
|
|
57
66
|
self._company_id = event.company_id
|
|
58
67
|
self._user_id = event.user_id
|
|
59
68
|
if isinstance(event, (ChatEvent, Event)):
|
|
60
69
|
self._chat_id = event.payload.chat_id
|
|
61
70
|
self._assistant_id = event.payload.assistant_id
|
|
71
|
+
elif isinstance(event, BaseEvent):
|
|
72
|
+
self._event = event
|
|
73
|
+
self._company_id = event.company_id
|
|
74
|
+
self._user_id = event.user_id
|
|
75
|
+
self._chat_id: str | None = None
|
|
76
|
+
self._assistant_id: str | None = None
|
|
62
77
|
else:
|
|
63
78
|
[company_id, user_id] = validate_required_values([company_id, user_id])
|
|
79
|
+
self._event = None
|
|
64
80
|
self._company_id: str = company_id
|
|
65
81
|
self._user_id: str = user_id
|
|
82
|
+
self._chat_id: str | None = None
|
|
83
|
+
self._assistant_id: str | None = None
|
|
84
|
+
|
|
85
|
+
@classmethod
|
|
86
|
+
def from_event(cls, event: BaseEvent):
|
|
87
|
+
"""
|
|
88
|
+
Initialize the LanguageModelService with an event.
|
|
89
|
+
"""
|
|
90
|
+
return cls(company_id=event.company_id, user_id=event.user_id)
|
|
66
91
|
|
|
67
92
|
@property
|
|
68
93
|
@deprecated(
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from typing import overload
|
|
2
|
+
|
|
1
3
|
from typing_extensions import deprecated
|
|
2
4
|
|
|
3
5
|
from unique_toolkit._common.validate_required_values import validate_required_values
|
|
@@ -16,17 +18,35 @@ from .schemas import ShortTermMemory
|
|
|
16
18
|
class ShortTermMemoryService:
|
|
17
19
|
"""
|
|
18
20
|
Provides methods to manage short term memory.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
@deprecated(
|
|
24
|
+
"Use __init__ with company_id and user_id instead or use the classmethod `from_event`"
|
|
25
|
+
)
|
|
26
|
+
@overload
|
|
27
|
+
def __init__(self, event: Event | ChatEvent | BaseEvent): ...
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
Initialize the ShortTermMemoryService with an event (deprecated)
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
@overload
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
*,
|
|
37
|
+
company_id: str,
|
|
38
|
+
user_id: str,
|
|
39
|
+
chat_id: str | None,
|
|
40
|
+
message_id: str | None,
|
|
41
|
+
): ...
|
|
19
42
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
company_id (str | None): The company ID.
|
|
23
|
-
chat_id (str | None): The chat ID.
|
|
24
|
-
message_id (str | None): The message ID.
|
|
43
|
+
"""
|
|
44
|
+
Initialize the ShortTermMemoryService with a company_id, user_id, chat_id and message_id.
|
|
25
45
|
"""
|
|
26
46
|
|
|
27
47
|
def __init__(
|
|
28
48
|
self,
|
|
29
|
-
event: Event | BaseEvent | None = None,
|
|
49
|
+
event: Event | ChatEvent | BaseEvent | None = None,
|
|
30
50
|
user_id: str | None = None,
|
|
31
51
|
company_id: str | None = None,
|
|
32
52
|
chat_id: str | None = None,
|
|
@@ -50,6 +70,18 @@ class ShortTermMemoryService:
|
|
|
50
70
|
self._chat_id: str | None = chat_id
|
|
51
71
|
self._message_id: str | None = message_id
|
|
52
72
|
|
|
73
|
+
@classmethod
|
|
74
|
+
def from_event(cls, event: ChatEvent):
|
|
75
|
+
"""
|
|
76
|
+
Initialize the ShortTermMemoryService with a chat event.
|
|
77
|
+
"""
|
|
78
|
+
return cls(
|
|
79
|
+
company_id=event.company_id,
|
|
80
|
+
user_id=event.user_id,
|
|
81
|
+
chat_id=event.payload.chat_id,
|
|
82
|
+
message_id=event.payload.user_message.id,
|
|
83
|
+
)
|
|
84
|
+
|
|
53
85
|
@property
|
|
54
86
|
@deprecated(
|
|
55
87
|
"The event property is deprecated and will be removed in a future version."
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from logging import getLogger
|
|
3
|
-
from typing import Literal, overload
|
|
4
|
-
|
|
5
|
-
from unique_toolkit.app import ChatEvent, EventName
|
|
6
|
-
|
|
7
|
-
LOGGER = getLogger(__name__)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@overload
|
|
11
|
-
def load_and_filter_event(
|
|
12
|
-
event: dict,
|
|
13
|
-
event_type: Literal[EventName.EXTERNAL_MODULE_CHOSEN],
|
|
14
|
-
) -> type[ChatEvent] | None: ...
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def load_and_filter_event(event: dict, event_type: EventName):
|
|
18
|
-
event = json.loads(event.data)
|
|
19
|
-
|
|
20
|
-
match event_type:
|
|
21
|
-
case EventName.EXTERNAL_MODULE_CHOSEN:
|
|
22
|
-
return ChatEvent(**event)
|
|
23
|
-
|
|
24
|
-
return None
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
from logging import getLogger
|
|
2
|
-
|
|
3
|
-
from sseclient import SSEClient
|
|
4
|
-
|
|
5
|
-
from unique_toolkit.app.unique_settings import UniqueSettings
|
|
6
|
-
|
|
7
|
-
LOGGER = getLogger(__name__)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def get_sse_client(
|
|
11
|
-
unique_settings: UniqueSettings,
|
|
12
|
-
subscriptions: list[str],
|
|
13
|
-
) -> SSEClient:
|
|
14
|
-
url = f"{unique_settings.app.base_url}/public/event-socket/events/stream?subscriptions={','.join(subscriptions)}"
|
|
15
|
-
headers = {
|
|
16
|
-
"Authorization": f"Bearer {unique_settings.app.key.get_secret_value()}",
|
|
17
|
-
"x-app-id": unique_settings.app.id.get_secret_value(),
|
|
18
|
-
"x-company-id": unique_settings.auth.company_id.get_secret_value(),
|
|
19
|
-
}
|
|
20
|
-
return SSEClient(url=url, headers=headers)
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
|
|
3
|
-
from pydantic import SecretStr
|
|
4
|
-
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class UniqueApp(BaseSettings):
|
|
8
|
-
id: SecretStr
|
|
9
|
-
key: SecretStr
|
|
10
|
-
base_url: str
|
|
11
|
-
endpoint: str
|
|
12
|
-
endpoint_secret: SecretStr
|
|
13
|
-
|
|
14
|
-
model_config = SettingsConfigDict(
|
|
15
|
-
env_prefix="unique_app_",
|
|
16
|
-
env_file_encoding="utf-8",
|
|
17
|
-
case_sensitive=False,
|
|
18
|
-
extra="ignore",
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class UniqueAuth(BaseSettings):
|
|
23
|
-
company_id: SecretStr
|
|
24
|
-
user_id: SecretStr
|
|
25
|
-
|
|
26
|
-
model_config = SettingsConfigDict(
|
|
27
|
-
env_prefix="unique_auth_",
|
|
28
|
-
env_file_encoding="utf-8",
|
|
29
|
-
case_sensitive=False,
|
|
30
|
-
extra="ignore",
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class UniqueSettings:
|
|
35
|
-
def __init__(self, auth: UniqueAuth, app: UniqueApp):
|
|
36
|
-
self.app = app
|
|
37
|
-
self.auth = auth
|
|
38
|
-
|
|
39
|
-
@classmethod
|
|
40
|
-
def from_env(cls, env_file: Path | None = None) -> "UniqueSettings":
|
|
41
|
-
"""Initialize settings from environment variables and/or env file.
|
|
42
|
-
|
|
43
|
-
Args:
|
|
44
|
-
env_file: Optional path to environment file. If provided, will load variables from this file.
|
|
45
|
-
|
|
46
|
-
Returns:
|
|
47
|
-
UniqueSettings instance with values loaded from environment/env file.
|
|
48
|
-
|
|
49
|
-
Raises:
|
|
50
|
-
FileNotFoundError: If env_file is provided but does not exist.
|
|
51
|
-
ValidationError: If required environment variables are missing.
|
|
52
|
-
"""
|
|
53
|
-
if env_file and not env_file.exists():
|
|
54
|
-
raise FileNotFoundError(f"Environment file not found: {env_file}")
|
|
55
|
-
|
|
56
|
-
# Initialize settings with environment file if provided
|
|
57
|
-
env_file_str = str(env_file) if env_file else None
|
|
58
|
-
auth = UniqueAuth(_env_file=env_file_str, _env_file_encoding="utf-8")
|
|
59
|
-
app = UniqueApp(_env_file=env_file_str, _env_file_encoding="utf-8")
|
|
60
|
-
|
|
61
|
-
return cls(auth=auth, app=app)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/_common/validate_required_values.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/app/performance/async_wrapper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/context_relevancy/prompts.py
RENAMED
|
File without changes
|
{unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/context_relevancy/service.py
RENAMED
|
File without changes
|
{unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/context_relevancy/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/hallucination/constants.py
RENAMED
|
File without changes
|
{unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/hallucination/prompts.py
RENAMED
|
File without changes
|
{unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/hallucination/service.py
RENAMED
|
File without changes
|
{unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/evaluators/hallucination/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_toolkit-0.8.1 → unique_toolkit-0.8.3}/unique_toolkit/tools/tool_progress_reporter.py
RENAMED
|
File without changes
|