smallestai 4.0.0__py3-none-any.whl → 4.1.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.
Potentially problematic release.
This version of smallestai might be problematic. Click here for more details.
- smallestai/__init__.py +34 -44
- smallestai/atoms/__init__.py +249 -123
- smallestai/atoms/api/__init__.py +0 -1
- smallestai/atoms/api/agent_templates_api.py +26 -26
- smallestai/atoms/api/agents_api.py +1316 -190
- smallestai/atoms/api/calls_api.py +29 -29
- smallestai/atoms/api/campaigns_api.py +165 -165
- smallestai/atoms/api/knowledge_base_api.py +290 -290
- smallestai/atoms/api/logs_api.py +13 -13
- smallestai/atoms/api/organization_api.py +13 -13
- smallestai/atoms/api/user_api.py +13 -13
- smallestai/atoms/atoms_client.py +77 -49
- smallestai/atoms/models/__init__.py +103 -43
- smallestai/atoms/models/agent_agent_id_webhook_subscriptions_delete200_response.py +89 -0
- smallestai/atoms/models/{get_agent_templates200_response.py → agent_agent_id_webhook_subscriptions_get200_response.py} +7 -7
- smallestai/atoms/models/agent_agent_id_webhook_subscriptions_get404_response.py +89 -0
- smallestai/atoms/models/agent_agent_id_webhook_subscriptions_post201_response.py +89 -0
- smallestai/atoms/models/agent_agent_id_webhook_subscriptions_post400_response.py +89 -0
- smallestai/atoms/models/agent_agent_id_webhook_subscriptions_post_request.py +97 -0
- smallestai/atoms/models/agent_dto.py +8 -6
- smallestai/atoms/models/agent_dto_language.py +17 -3
- smallestai/atoms/models/agent_dto_language_switching.py +95 -0
- smallestai/atoms/models/agent_dto_synthesizer.py +1 -1
- smallestai/atoms/models/{create_agent_from_template200_response.py → agent_from_template_post200_response.py} +4 -4
- smallestai/atoms/models/{get_agents200_response.py → agent_get200_response.py} +7 -7
- smallestai/atoms/models/{get_agents200_response_data.py → agent_get200_response_data.py} +9 -13
- smallestai/atoms/models/{delete_agent200_response.py → agent_id_delete200_response.py} +4 -4
- smallestai/atoms/models/{get_agent_by_id200_response.py → agent_id_get200_response.py} +4 -4
- smallestai/atoms/models/{update_agent200_response.py → agent_id_patch200_response.py} +4 -4
- smallestai/atoms/models/{update_agent_request.py → agent_id_patch_request.py} +17 -15
- smallestai/atoms/models/{update_agent_request_language.py → agent_id_patch_request_language.py} +14 -10
- smallestai/atoms/models/agent_id_patch_request_language_switching.py +96 -0
- smallestai/atoms/models/{update_agent_request_synthesizer.py → agent_id_patch_request_synthesizer.py} +6 -6
- smallestai/atoms/models/{update_agent_request_synthesizer_voice_config.py → agent_id_patch_request_synthesizer_voice_config.py} +27 -27
- smallestai/atoms/models/{update_agent_request_synthesizer_voice_config_one_of.py → agent_id_patch_request_synthesizer_voice_config_one_of.py} +4 -4
- smallestai/atoms/models/{update_agent_request_synthesizer_voice_config_one_of1.py → agent_id_patch_request_synthesizer_voice_config_one_of1.py} +4 -4
- smallestai/atoms/models/{get_campaign_by_id200_response.py → agent_id_workflow_get200_response.py} +7 -7
- smallestai/atoms/models/agent_id_workflow_get200_response_data.py +105 -0
- smallestai/atoms/models/agent_id_workflow_get200_response_data_edges_inner.py +127 -0
- smallestai/atoms/models/agent_id_workflow_get200_response_data_edges_inner_data.py +91 -0
- smallestai/atoms/models/agent_id_workflow_get200_response_data_edges_inner_marker_end.py +91 -0
- smallestai/atoms/models/agent_id_workflow_get200_response_data_nodes_inner.py +114 -0
- smallestai/atoms/models/agent_id_workflow_get200_response_data_nodes_inner_data.py +115 -0
- smallestai/atoms/models/agent_id_workflow_get200_response_data_nodes_inner_data_variables.py +97 -0
- smallestai/atoms/models/agent_id_workflow_get200_response_data_nodes_inner_data_variables_data_inner.py +91 -0
- smallestai/atoms/models/agent_id_workflow_get200_response_data_nodes_inner_position.py +89 -0
- smallestai/atoms/models/agent_id_workflow_get404_response.py +89 -0
- smallestai/atoms/models/agent_template_get200_response.py +97 -0
- smallestai/atoms/models/{get_agent_templates200_response_data_inner.py → agent_template_get200_response_data_inner.py} +6 -6
- smallestai/atoms/models/{get_campaigns200_response.py → audience_get200_response.py} +7 -7
- smallestai/atoms/models/{create_campaign201_response_data.py → audience_get200_response_data_inner.py} +16 -18
- smallestai/atoms/models/audience_id_delete200_response.py +89 -0
- smallestai/atoms/models/audience_id_delete400_response.py +89 -0
- smallestai/atoms/models/{get_current_user200_response.py → audience_id_get200_response.py} +7 -7
- smallestai/atoms/models/audience_id_get400_response.py +89 -0
- smallestai/atoms/models/audience_id_get403_response.py +89 -0
- smallestai/atoms/models/audience_id_get404_response.py +89 -0
- smallestai/atoms/models/audience_id_members_delete200_response.py +93 -0
- smallestai/atoms/models/audience_id_members_delete200_response_data.py +87 -0
- smallestai/atoms/models/audience_id_members_delete_request.py +87 -0
- smallestai/atoms/models/audience_id_members_get200_response.py +93 -0
- smallestai/atoms/models/audience_id_members_get200_response_data.py +101 -0
- smallestai/atoms/models/{get_campaigns200_response_data_inner_audience.py → audience_id_members_get200_response_data_members_inner.py} +8 -8
- smallestai/atoms/models/audience_id_members_get400_response.py +89 -0
- smallestai/atoms/models/audience_id_members_get500_response.py +89 -0
- smallestai/atoms/models/audience_id_members_post200_response.py +97 -0
- smallestai/atoms/models/audience_id_members_post200_response_data_inner.py +93 -0
- smallestai/atoms/models/audience_id_members_post200_response_data_inner_data.py +89 -0
- smallestai/atoms/models/audience_id_members_post400_response.py +89 -0
- smallestai/atoms/models/audience_id_members_post403_response.py +89 -0
- smallestai/atoms/models/audience_id_members_post_request.py +87 -0
- smallestai/atoms/models/audience_id_members_search_get200_response.py +93 -0
- smallestai/atoms/models/audience_id_members_search_get200_response_data.py +101 -0
- smallestai/atoms/models/audience_id_members_search_get200_response_data_search_info.py +103 -0
- smallestai/atoms/models/audience_id_members_search_get400_response.py +89 -0
- smallestai/atoms/models/audience_id_members_search_get500_response.py +89 -0
- smallestai/atoms/models/{create_campaign201_response.py → audience_post200_response.py} +7 -7
- smallestai/atoms/models/audience_post200_response_data.py +104 -0
- smallestai/atoms/models/audience_post400_response.py +89 -0
- smallestai/atoms/models/campaign_get200_response.py +93 -0
- smallestai/atoms/models/campaign_get200_response_data.py +87 -0
- smallestai/atoms/models/{get_campaigns_request.py → campaign_get_request.py} +4 -4
- smallestai/atoms/models/campaign_id_get200_response.py +93 -0
- smallestai/atoms/models/{get_campaign_by_id200_response_data.py → campaign_id_get200_response_data.py} +4 -4
- smallestai/atoms/models/campaign_post201_response.py +89 -0
- smallestai/atoms/models/{create_campaign_request.py → campaign_post_request.py} +4 -4
- smallestai/atoms/models/{start_outbound_call200_response.py → conversation_id_get200_response.py} +7 -7
- smallestai/atoms/models/{get_conversation_logs200_response_data.py → conversation_id_get200_response_data.py} +4 -4
- smallestai/atoms/models/conversation_outbound_post200_response.py +93 -0
- smallestai/atoms/models/{start_outbound_call200_response_data.py → conversation_outbound_post200_response_data.py} +4 -4
- smallestai/atoms/models/{start_outbound_call_request.py → conversation_outbound_post_request.py} +4 -4
- smallestai/atoms/models/create_agent_request.py +10 -6
- smallestai/atoms/models/create_agent_request_language.py +11 -7
- smallestai/atoms/models/create_agent_request_language_synthesizer_voice_config.py +24 -24
- smallestai/atoms/models/{knowledge_base_dto.py → knowledge_base.py} +15 -8
- smallestai/atoms/models/{knowledge_base_item_dto.py → knowledge_base_item.py} +19 -17
- smallestai/atoms/models/{get_knowledge_bases200_response.py → knowledgebase_get200_response.py} +7 -7
- smallestai/atoms/models/{get_knowledge_base_by_id200_response.py → knowledgebase_id_get200_response.py} +7 -7
- smallestai/atoms/models/{get_knowledge_base_items200_response.py → knowledgebase_id_items_get200_response.py} +7 -7
- smallestai/atoms/models/{upload_text_to_knowledge_base_request.py → knowledgebase_id_items_upload_text_post_request.py} +4 -4
- smallestai/atoms/models/{create_knowledge_base201_response.py → knowledgebase_post201_response.py} +4 -4
- smallestai/atoms/models/{create_knowledge_base_request.py → knowledgebase_post_request.py} +4 -4
- smallestai/atoms/models/{get_organization200_response.py → organization_get200_response.py} +7 -7
- smallestai/atoms/models/{get_organization200_response_data.py → organization_get200_response_data.py} +10 -10
- smallestai/atoms/models/{get_organization200_response_data_members_inner.py → organization_get200_response_data_members_inner.py} +4 -4
- smallestai/atoms/models/{get_organization200_response_data_subscription.py → organization_get200_response_data_subscription.py} +4 -4
- smallestai/atoms/models/product_phone_numbers_get200_response.py +97 -0
- smallestai/atoms/models/product_phone_numbers_get200_response_data_inner.py +100 -0
- smallestai/atoms/models/product_phone_numbers_get200_response_data_inner_attributes.py +89 -0
- smallestai/atoms/models/user_get200_response.py +93 -0
- smallestai/atoms/models/{get_current_user200_response_data.py → user_get200_response_data.py} +4 -4
- smallestai/atoms/models/webhook.py +124 -0
- smallestai/atoms/models/{get_campaigns200_response_data_inner_agent.py → webhook_agent.py} +8 -6
- smallestai/atoms/models/webhook_event.py +98 -0
- smallestai/atoms/models/webhook_get200_response.py +93 -0
- smallestai/atoms/models/webhook_get200_response_data.py +140 -0
- smallestai/atoms/models/webhook_id_delete404_response.py +89 -0
- smallestai/atoms/models/webhook_post201_response.py +89 -0
- smallestai/atoms/models/webhook_post_request.py +99 -0
- smallestai/atoms/models/webhook_post_request_events_inner.py +99 -0
- smallestai/atoms/models/webhook_subscription.py +108 -0
- smallestai/atoms/models/webhook_subscription_populated.py +112 -0
- smallestai/waves/async_waves_client.py +63 -10
- smallestai/waves/exceptions.py +4 -4
- smallestai/waves/models.py +8 -0
- smallestai/waves/utils.py +19 -1
- smallestai/waves/waves_client.py +47 -10
- {smallestai-4.0.0.dist-info → smallestai-4.1.0.dist-info}/METADATA +2 -2
- smallestai-4.1.0.dist-info/RECORD +147 -0
- smallestai/atoms/models/get_campaigns200_response_data_inner.py +0 -118
- smallestai/atoms/models/get_conversation_logs200_response.py +0 -93
- smallestai-4.0.0.dist-info/RECORD +0 -87
- {smallestai-4.0.0.dist-info → smallestai-4.1.0.dist-info}/WHEEL +0 -0
- {smallestai-4.0.0.dist-info → smallestai-4.1.0.dist-info}/licenses/LICENSE +0 -0
- {smallestai-4.0.0.dist-info → smallestai-4.1.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Agent Management API
|
|
5
|
+
|
|
6
|
+
API for managing agents, their templates, and call logs
|
|
7
|
+
|
|
8
|
+
The version of the OpenAPI document: 1.0.0
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import pprint
|
|
17
|
+
import re # noqa: F401
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator
|
|
21
|
+
from typing import Any, ClassVar, Dict, List, Optional
|
|
22
|
+
from typing import Optional, Set
|
|
23
|
+
from typing_extensions import Self
|
|
24
|
+
|
|
25
|
+
class WebhookPostRequestEventsInner(BaseModel):
|
|
26
|
+
"""
|
|
27
|
+
WebhookPostRequestEventsInner
|
|
28
|
+
""" # noqa: E501
|
|
29
|
+
agent_id: Optional[StrictStr] = Field(default=None, description="The ID of the agent", alias="agentId")
|
|
30
|
+
event_type: Optional[StrictStr] = Field(default=None, description="The type of event to subscribe to", alias="eventType")
|
|
31
|
+
__properties: ClassVar[List[str]] = ["agentId", "eventType"]
|
|
32
|
+
|
|
33
|
+
@field_validator('event_type')
|
|
34
|
+
def event_type_validate_enum(cls, value):
|
|
35
|
+
"""Validates the enum"""
|
|
36
|
+
if value is None:
|
|
37
|
+
return value
|
|
38
|
+
|
|
39
|
+
if value not in set(['pre-conversation', 'post-conversation']):
|
|
40
|
+
raise ValueError("must be one of enum values ('pre-conversation', 'post-conversation')")
|
|
41
|
+
return value
|
|
42
|
+
|
|
43
|
+
model_config = ConfigDict(
|
|
44
|
+
populate_by_name=True,
|
|
45
|
+
validate_assignment=True,
|
|
46
|
+
protected_namespaces=(),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def to_str(self) -> str:
|
|
51
|
+
"""Returns the string representation of the model using alias"""
|
|
52
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
|
53
|
+
|
|
54
|
+
def to_json(self) -> str:
|
|
55
|
+
"""Returns the JSON representation of the model using alias"""
|
|
56
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
|
57
|
+
return json.dumps(self.to_dict())
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
|
61
|
+
"""Create an instance of WebhookPostRequestEventsInner from a JSON string"""
|
|
62
|
+
return cls.from_dict(json.loads(json_str))
|
|
63
|
+
|
|
64
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
65
|
+
"""Return the dictionary representation of the model using alias.
|
|
66
|
+
|
|
67
|
+
This has the following differences from calling pydantic's
|
|
68
|
+
`self.model_dump(by_alias=True)`:
|
|
69
|
+
|
|
70
|
+
* `None` is only added to the output dict for nullable fields that
|
|
71
|
+
were set at model initialization. Other fields with value `None`
|
|
72
|
+
are ignored.
|
|
73
|
+
"""
|
|
74
|
+
excluded_fields: Set[str] = set([
|
|
75
|
+
])
|
|
76
|
+
|
|
77
|
+
_dict = self.model_dump(
|
|
78
|
+
by_alias=True,
|
|
79
|
+
exclude=excluded_fields,
|
|
80
|
+
exclude_none=True,
|
|
81
|
+
)
|
|
82
|
+
return _dict
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
|
86
|
+
"""Create an instance of WebhookPostRequestEventsInner from a dict"""
|
|
87
|
+
if obj is None:
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
if not isinstance(obj, dict):
|
|
91
|
+
return cls.model_validate(obj)
|
|
92
|
+
|
|
93
|
+
_obj = cls.model_validate({
|
|
94
|
+
"agentId": obj.get("agentId"),
|
|
95
|
+
"eventType": obj.get("eventType")
|
|
96
|
+
})
|
|
97
|
+
return _obj
|
|
98
|
+
|
|
99
|
+
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Agent Management API
|
|
5
|
+
|
|
6
|
+
API for managing agents, their templates, and call logs
|
|
7
|
+
|
|
8
|
+
The version of the OpenAPI document: 1.0.0
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import pprint
|
|
17
|
+
import re # noqa: F401
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator
|
|
22
|
+
from typing import Any, ClassVar, Dict, List, Optional
|
|
23
|
+
from typing import Optional, Set
|
|
24
|
+
from typing_extensions import Self
|
|
25
|
+
|
|
26
|
+
class WebhookSubscription(BaseModel):
|
|
27
|
+
"""
|
|
28
|
+
WebhookSubscription
|
|
29
|
+
""" # noqa: E501
|
|
30
|
+
id: Optional[StrictStr] = Field(default=None, description="The unique identifier for the subscription", alias="_id")
|
|
31
|
+
webhook_id: Optional[StrictStr] = Field(default=None, description="The ID of the webhook", alias="webhookId")
|
|
32
|
+
agent_id: Optional[StrictStr] = Field(default=None, description="The ID of the agent", alias="agentId")
|
|
33
|
+
event_type: Optional[StrictStr] = Field(default=None, description="The type of event subscribed to", alias="eventType")
|
|
34
|
+
created_at: Optional[datetime] = Field(default=None, description="The date and time when the subscription was created", alias="createdAt")
|
|
35
|
+
updated_at: Optional[datetime] = Field(default=None, description="The date and time when the subscription was last updated", alias="updatedAt")
|
|
36
|
+
__properties: ClassVar[List[str]] = ["_id", "webhookId", "agentId", "eventType", "createdAt", "updatedAt"]
|
|
37
|
+
|
|
38
|
+
@field_validator('event_type')
|
|
39
|
+
def event_type_validate_enum(cls, value):
|
|
40
|
+
"""Validates the enum"""
|
|
41
|
+
if value is None:
|
|
42
|
+
return value
|
|
43
|
+
|
|
44
|
+
if value not in set(['pre-conversation', 'post-conversation']):
|
|
45
|
+
raise ValueError("must be one of enum values ('pre-conversation', 'post-conversation')")
|
|
46
|
+
return value
|
|
47
|
+
|
|
48
|
+
model_config = ConfigDict(
|
|
49
|
+
populate_by_name=True,
|
|
50
|
+
validate_assignment=True,
|
|
51
|
+
protected_namespaces=(),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def to_str(self) -> str:
|
|
56
|
+
"""Returns the string representation of the model using alias"""
|
|
57
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
|
58
|
+
|
|
59
|
+
def to_json(self) -> str:
|
|
60
|
+
"""Returns the JSON representation of the model using alias"""
|
|
61
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
|
62
|
+
return json.dumps(self.to_dict())
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
|
66
|
+
"""Create an instance of WebhookSubscription from a JSON string"""
|
|
67
|
+
return cls.from_dict(json.loads(json_str))
|
|
68
|
+
|
|
69
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
70
|
+
"""Return the dictionary representation of the model using alias.
|
|
71
|
+
|
|
72
|
+
This has the following differences from calling pydantic's
|
|
73
|
+
`self.model_dump(by_alias=True)`:
|
|
74
|
+
|
|
75
|
+
* `None` is only added to the output dict for nullable fields that
|
|
76
|
+
were set at model initialization. Other fields with value `None`
|
|
77
|
+
are ignored.
|
|
78
|
+
"""
|
|
79
|
+
excluded_fields: Set[str] = set([
|
|
80
|
+
])
|
|
81
|
+
|
|
82
|
+
_dict = self.model_dump(
|
|
83
|
+
by_alias=True,
|
|
84
|
+
exclude=excluded_fields,
|
|
85
|
+
exclude_none=True,
|
|
86
|
+
)
|
|
87
|
+
return _dict
|
|
88
|
+
|
|
89
|
+
@classmethod
|
|
90
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
|
91
|
+
"""Create an instance of WebhookSubscription from a dict"""
|
|
92
|
+
if obj is None:
|
|
93
|
+
return None
|
|
94
|
+
|
|
95
|
+
if not isinstance(obj, dict):
|
|
96
|
+
return cls.model_validate(obj)
|
|
97
|
+
|
|
98
|
+
_obj = cls.model_validate({
|
|
99
|
+
"_id": obj.get("_id"),
|
|
100
|
+
"webhookId": obj.get("webhookId"),
|
|
101
|
+
"agentId": obj.get("agentId"),
|
|
102
|
+
"eventType": obj.get("eventType"),
|
|
103
|
+
"createdAt": obj.get("createdAt"),
|
|
104
|
+
"updatedAt": obj.get("updatedAt")
|
|
105
|
+
})
|
|
106
|
+
return _obj
|
|
107
|
+
|
|
108
|
+
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Agent Management API
|
|
5
|
+
|
|
6
|
+
API for managing agents, their templates, and call logs
|
|
7
|
+
|
|
8
|
+
The version of the OpenAPI document: 1.0.0
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import pprint
|
|
17
|
+
import re # noqa: F401
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator
|
|
22
|
+
from typing import Any, ClassVar, Dict, List, Optional
|
|
23
|
+
from smallestai.atoms.models.webhook_agent import WebhookAgent
|
|
24
|
+
from typing import Optional, Set
|
|
25
|
+
from typing_extensions import Self
|
|
26
|
+
|
|
27
|
+
class WebhookSubscriptionPopulated(BaseModel):
|
|
28
|
+
"""
|
|
29
|
+
WebhookSubscriptionPopulated
|
|
30
|
+
""" # noqa: E501
|
|
31
|
+
id: Optional[StrictStr] = Field(default=None, description="The unique identifier for the subscription", alias="_id")
|
|
32
|
+
webhook_id: Optional[StrictStr] = Field(default=None, description="The ID of the webhook", alias="webhookId")
|
|
33
|
+
agent_id: Optional[WebhookAgent] = Field(default=None, alias="agentId")
|
|
34
|
+
event_type: Optional[StrictStr] = Field(default=None, description="The type of event subscribed to", alias="eventType")
|
|
35
|
+
created_at: Optional[datetime] = Field(default=None, description="The date and time when the subscription was created", alias="createdAt")
|
|
36
|
+
updated_at: Optional[datetime] = Field(default=None, description="The date and time when the subscription was last updated", alias="updatedAt")
|
|
37
|
+
__properties: ClassVar[List[str]] = ["_id", "webhookId", "agentId", "eventType", "createdAt", "updatedAt"]
|
|
38
|
+
|
|
39
|
+
@field_validator('event_type')
|
|
40
|
+
def event_type_validate_enum(cls, value):
|
|
41
|
+
"""Validates the enum"""
|
|
42
|
+
if value is None:
|
|
43
|
+
return value
|
|
44
|
+
|
|
45
|
+
if value not in set(['pre-conversation', 'post-conversation']):
|
|
46
|
+
raise ValueError("must be one of enum values ('pre-conversation', 'post-conversation')")
|
|
47
|
+
return value
|
|
48
|
+
|
|
49
|
+
model_config = ConfigDict(
|
|
50
|
+
populate_by_name=True,
|
|
51
|
+
validate_assignment=True,
|
|
52
|
+
protected_namespaces=(),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def to_str(self) -> str:
|
|
57
|
+
"""Returns the string representation of the model using alias"""
|
|
58
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
|
59
|
+
|
|
60
|
+
def to_json(self) -> str:
|
|
61
|
+
"""Returns the JSON representation of the model using alias"""
|
|
62
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
|
63
|
+
return json.dumps(self.to_dict())
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
|
67
|
+
"""Create an instance of WebhookSubscriptionPopulated from a JSON string"""
|
|
68
|
+
return cls.from_dict(json.loads(json_str))
|
|
69
|
+
|
|
70
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
71
|
+
"""Return the dictionary representation of the model using alias.
|
|
72
|
+
|
|
73
|
+
This has the following differences from calling pydantic's
|
|
74
|
+
`self.model_dump(by_alias=True)`:
|
|
75
|
+
|
|
76
|
+
* `None` is only added to the output dict for nullable fields that
|
|
77
|
+
were set at model initialization. Other fields with value `None`
|
|
78
|
+
are ignored.
|
|
79
|
+
"""
|
|
80
|
+
excluded_fields: Set[str] = set([
|
|
81
|
+
])
|
|
82
|
+
|
|
83
|
+
_dict = self.model_dump(
|
|
84
|
+
by_alias=True,
|
|
85
|
+
exclude=excluded_fields,
|
|
86
|
+
exclude_none=True,
|
|
87
|
+
)
|
|
88
|
+
# override the default output from pydantic by calling `to_dict()` of agent_id
|
|
89
|
+
if self.agent_id:
|
|
90
|
+
_dict['agentId'] = self.agent_id.to_dict()
|
|
91
|
+
return _dict
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
|
95
|
+
"""Create an instance of WebhookSubscriptionPopulated from a dict"""
|
|
96
|
+
if obj is None:
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
if not isinstance(obj, dict):
|
|
100
|
+
return cls.model_validate(obj)
|
|
101
|
+
|
|
102
|
+
_obj = cls.model_validate({
|
|
103
|
+
"_id": obj.get("_id"),
|
|
104
|
+
"webhookId": obj.get("webhookId"),
|
|
105
|
+
"agentId": WebhookAgent.from_dict(obj["agentId"]) if obj.get("agentId") is not None else None,
|
|
106
|
+
"eventType": obj.get("eventType"),
|
|
107
|
+
"createdAt": obj.get("createdAt"),
|
|
108
|
+
"updatedAt": obj.get("updatedAt")
|
|
109
|
+
})
|
|
110
|
+
return _obj
|
|
111
|
+
|
|
112
|
+
|
|
@@ -6,8 +6,8 @@ import aiofiles
|
|
|
6
6
|
import requests
|
|
7
7
|
from typing import Optional, Union, List
|
|
8
8
|
|
|
9
|
-
from smallestai.waves.exceptions import
|
|
10
|
-
from smallestai.waves.utils import (TTSOptions, validate_input,
|
|
9
|
+
from smallestai.waves.exceptions import InvalidError, APIError
|
|
10
|
+
from smallestai.waves.utils import (TTSOptions, validate_input, validate_asr_input,
|
|
11
11
|
get_smallest_languages, get_smallest_models, ALLOWED_AUDIO_EXTENSIONS, API_BASE_URL)
|
|
12
12
|
|
|
13
13
|
|
|
@@ -52,7 +52,7 @@ class AsyncWavesClient:
|
|
|
52
52
|
"""
|
|
53
53
|
self.api_key = api_key or os.environ.get("SMALLEST_API_KEY")
|
|
54
54
|
if not self.api_key:
|
|
55
|
-
raise
|
|
55
|
+
raise InvalidError()
|
|
56
56
|
if model == "lightning-large" and voice_id is None:
|
|
57
57
|
voice_id = "lakshya"
|
|
58
58
|
|
|
@@ -150,7 +150,7 @@ class AsyncWavesClient:
|
|
|
150
150
|
- Otherwise, returns the synthesized audio content as bytes.
|
|
151
151
|
|
|
152
152
|
Raises:
|
|
153
|
-
-
|
|
153
|
+
- InvalidError: If the provided file name does not have a .wav or .mp3 extension when `save_as` is specified.
|
|
154
154
|
- APIError: If the API request fails or returns an error.
|
|
155
155
|
- ValueError: If an unexpected parameter is passed in `kwargs`.
|
|
156
156
|
"""
|
|
@@ -223,17 +223,17 @@ class AsyncWavesClient:
|
|
|
223
223
|
- str: The response from the API as a formatted JSON string.
|
|
224
224
|
|
|
225
225
|
Raises:
|
|
226
|
-
-
|
|
226
|
+
- InvalidError: If the file does not exist or is not a valid audio file.
|
|
227
227
|
- APIError: If the API request fails or returns an error.
|
|
228
228
|
"""
|
|
229
229
|
url = f"{API_BASE_URL}/lightning-large/add_voice"
|
|
230
230
|
|
|
231
231
|
if not os.path.exists(file_path):
|
|
232
|
-
raise
|
|
232
|
+
raise InvalidError("Invalid file path. File does not exist.")
|
|
233
233
|
|
|
234
234
|
file_extension = os.path.splitext(file_path)[1].lower()
|
|
235
235
|
if file_extension not in ALLOWED_AUDIO_EXTENSIONS:
|
|
236
|
-
raise
|
|
236
|
+
raise InvalidError(f"Invalid file type. Supported formats are: {ALLOWED_AUDIO_EXTENSIONS}")
|
|
237
237
|
|
|
238
238
|
headers = {
|
|
239
239
|
'Authorization': f"Bearer {self.api_key}",
|
|
@@ -255,7 +255,7 @@ class AsyncWavesClient:
|
|
|
255
255
|
if res.status != 200:
|
|
256
256
|
raise APIError(f"Failed to add voice: {await res.text()}. For more information, visit https://waves.smallest.ai/")
|
|
257
257
|
|
|
258
|
-
return
|
|
258
|
+
return await res.json()
|
|
259
259
|
|
|
260
260
|
finally:
|
|
261
261
|
if should_cleanup and self.session:
|
|
@@ -290,8 +290,61 @@ class AsyncWavesClient:
|
|
|
290
290
|
if res.status != 200:
|
|
291
291
|
raise APIError(f"Failed to delete voice: {await res.text()}. For more information, visit https://waves.smallest.ai/")
|
|
292
292
|
|
|
293
|
-
return
|
|
293
|
+
return await res.json()
|
|
294
294
|
finally:
|
|
295
295
|
if should_cleanup and self.session:
|
|
296
296
|
await self.session.close()
|
|
297
|
-
self.session = None
|
|
297
|
+
self.session = None
|
|
298
|
+
|
|
299
|
+
async def transcribe(
|
|
300
|
+
self,
|
|
301
|
+
file_path: str,
|
|
302
|
+
language: Optional[str] = "en",
|
|
303
|
+
word_timestamps: Optional[bool] = False,
|
|
304
|
+
age_detection: Optional[bool] = False,
|
|
305
|
+
gender_detection: Optional[bool] = False,
|
|
306
|
+
emotion_detection: Optional[bool] = False,
|
|
307
|
+
model: Optional[str] = "lightning"
|
|
308
|
+
) -> dict:
|
|
309
|
+
validate_asr_input(file_path, model, language)
|
|
310
|
+
|
|
311
|
+
url = f"{API_BASE_URL}/speech-to-text"
|
|
312
|
+
headers = {
|
|
313
|
+
'Authorization': f"Bearer {self.api_key}",
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
should_cleanup = await self._ensure_session()
|
|
317
|
+
|
|
318
|
+
try:
|
|
319
|
+
file_extension = os.path.splitext(file_path)[1].lower()
|
|
320
|
+
content_type = f"audio/{file_extension[1:]}" if file_extension else "application/octet-stream"
|
|
321
|
+
|
|
322
|
+
async with aiofiles.open(file_path, 'rb') as f:
|
|
323
|
+
file_data = await f.read()
|
|
324
|
+
|
|
325
|
+
form = aiohttp.FormData()
|
|
326
|
+
form.add_field(
|
|
327
|
+
'file',
|
|
328
|
+
file_data,
|
|
329
|
+
filename=os.path.basename(file_path),
|
|
330
|
+
content_type=content_type
|
|
331
|
+
)
|
|
332
|
+
# Send options as multipart form fields (not query params)
|
|
333
|
+
form.add_field('model', model)
|
|
334
|
+
form.add_field('language', language)
|
|
335
|
+
form.add_field('word_timestamps', str(bool(word_timestamps)).lower())
|
|
336
|
+
form.add_field('age_detection', str(bool(age_detection)).lower())
|
|
337
|
+
form.add_field('gender_detection', str(bool(gender_detection)).lower())
|
|
338
|
+
form.add_field('emotion_detection', str(bool(emotion_detection)).lower())
|
|
339
|
+
|
|
340
|
+
async with self.session.post(url, headers=headers, data=form) as res:
|
|
341
|
+
if res.status != 200:
|
|
342
|
+
raise APIError(
|
|
343
|
+
f"Failed to transcribe audio: {await res.text()}. "
|
|
344
|
+
"For more information, visit https://waves-docs.smallest.ai/v4.0.0/content/api-references/asr-post-api"
|
|
345
|
+
)
|
|
346
|
+
return await res.json()
|
|
347
|
+
finally:
|
|
348
|
+
if should_cleanup and self.session:
|
|
349
|
+
await self.session.close()
|
|
350
|
+
self.session = None
|
smallestai/waves/exceptions.py
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
class
|
|
1
|
+
class InvalidError(Exception):
|
|
2
2
|
"""Base exception for TTS SDK"""
|
|
3
3
|
default_message = "API key is required. Please set the `SMALLEST_API_KEY` environment variable or visit https://waves.smallest.ai/ to obtain your API key."
|
|
4
4
|
|
|
5
5
|
def __init__(self, message=None):
|
|
6
6
|
super().__init__(message or self.default_message)
|
|
7
7
|
|
|
8
|
-
class APIError(
|
|
8
|
+
class APIError(InvalidError):
|
|
9
9
|
"""Raised when the API returns an error"""
|
|
10
10
|
pass
|
|
11
11
|
|
|
12
|
-
class ValidationError(
|
|
12
|
+
class ValidationError(InvalidError):
|
|
13
13
|
"""Raised when input validation fails"""
|
|
14
14
|
pass
|
|
15
15
|
|
|
16
|
-
class AuthenticationError(
|
|
16
|
+
class AuthenticationError(InvalidError):
|
|
17
17
|
"""Raised when authentication fails"""
|
|
18
18
|
pass
|
smallestai/waves/models.py
CHANGED
|
@@ -6,3 +6,11 @@ TTSModels = [
|
|
|
6
6
|
"lightning-large",
|
|
7
7
|
"lightning-v2"
|
|
8
8
|
]
|
|
9
|
+
ASRLanguages_lightning = [
|
|
10
|
+
"it", "es", "en", "pt", "hi", "de", "fr", "uk", "ru", "kn", "ml", "pl",
|
|
11
|
+
"mr", "gu", "cs", "sk", "te", "or", "nl", "bn", "lv", "et", "ro", "pa",
|
|
12
|
+
"fi", "sv", "bg", "ta", "hu", "da", "lt", "mt", "multi"
|
|
13
|
+
]
|
|
14
|
+
ASRModels = [
|
|
15
|
+
"lightning"
|
|
16
|
+
]
|
smallestai/waves/utils.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import os
|
|
1
2
|
from typing import List
|
|
2
3
|
from typing import Optional
|
|
3
4
|
from dataclasses import dataclass
|
|
4
5
|
|
|
5
6
|
from smallestai.waves.exceptions import ValidationError
|
|
6
|
-
from smallestai.waves.models import TTSModels, TTSLanguages_lightning, TTSLanguages_lightning_large, TTSLanguages_lightning_v2
|
|
7
|
+
from smallestai.waves.models import TTSModels, TTSLanguages_lightning, TTSLanguages_lightning_large, TTSLanguages_lightning_v2, ASRModels, ASRLanguages_lightning
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
API_BASE_URL = "https://waves-api.smallest.ai/api/v1"
|
|
@@ -25,7 +26,24 @@ class TTSOptions:
|
|
|
25
26
|
enhancement: int
|
|
26
27
|
language: str
|
|
27
28
|
output_format: str
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class ASROptions:
|
|
32
|
+
model: str
|
|
33
|
+
api_key: str
|
|
34
|
+
language: str
|
|
35
|
+
word_timestamps: bool
|
|
36
|
+
age_detection: bool
|
|
37
|
+
gender_detection: bool
|
|
38
|
+
emotion_detection: bool
|
|
28
39
|
|
|
40
|
+
def validate_asr_input(file_path: str, model: str, language: str):
|
|
41
|
+
if not os.path.isfile(file_path):
|
|
42
|
+
raise ValidationError("Invalid file path. File does not exist.")
|
|
43
|
+
if model not in ASRModels:
|
|
44
|
+
raise ValidationError(f"Invalid model: {model}. Must be one of {ASRModels}")
|
|
45
|
+
if language not in ASRLanguages_lightning:
|
|
46
|
+
raise ValidationError(f"Invalid language: {language}. Must be one of {ASRLanguages_lightning}")
|
|
29
47
|
|
|
30
48
|
def validate_input(text: str, model: str, sample_rate: int, speed: float, consistency: Optional[float] = None, similarity: Optional[float] = None, enhancement: Optional[int] = None):
|
|
31
49
|
if not text:
|
smallestai/waves/waves_client.py
CHANGED
|
@@ -4,8 +4,8 @@ import copy
|
|
|
4
4
|
import requests
|
|
5
5
|
from typing import Optional, Union, List
|
|
6
6
|
|
|
7
|
-
from smallestai.waves.exceptions import
|
|
8
|
-
from smallestai.waves.utils import (TTSOptions, validate_input,
|
|
7
|
+
from smallestai.waves.exceptions import InvalidError, APIError
|
|
8
|
+
from smallestai.waves.utils import (TTSOptions, validate_input, validate_asr_input,
|
|
9
9
|
get_smallest_languages, get_smallest_models, ALLOWED_AUDIO_EXTENSIONS, API_BASE_URL)
|
|
10
10
|
|
|
11
11
|
class WavesClient:
|
|
@@ -48,7 +48,7 @@ class WavesClient:
|
|
|
48
48
|
"""
|
|
49
49
|
self.api_key = api_key or os.environ.get("SMALLEST_API_KEY")
|
|
50
50
|
if not self.api_key:
|
|
51
|
-
raise
|
|
51
|
+
raise InvalidError()
|
|
52
52
|
if model == "lightning-large" and voice_id is None:
|
|
53
53
|
voice_id = "lakshya"
|
|
54
54
|
|
|
@@ -125,7 +125,7 @@ class WavesClient:
|
|
|
125
125
|
- Otherwise, returns the synthesized audio content as bytes.
|
|
126
126
|
|
|
127
127
|
Raises:
|
|
128
|
-
-
|
|
128
|
+
- InvalidError: If the provided file name does not have a .wav or .mp3 extension when `save_as` is specified.
|
|
129
129
|
- APIError: If the API request fails or returns an error.
|
|
130
130
|
"""
|
|
131
131
|
opts = copy.deepcopy(self.opts)
|
|
@@ -184,15 +184,15 @@ class WavesClient:
|
|
|
184
184
|
- str: The response from the API as a formatted JSON string.
|
|
185
185
|
|
|
186
186
|
Raises:
|
|
187
|
-
-
|
|
187
|
+
- InvalidError: If the file does not exist or is not a valid audio file.
|
|
188
188
|
- APIError: If the API request fails or returns an error.
|
|
189
189
|
"""
|
|
190
190
|
if not os.path.isfile(file_path):
|
|
191
|
-
raise
|
|
191
|
+
raise InvalidError("Invalid file path. File does not exist.")
|
|
192
192
|
|
|
193
193
|
file_extension = os.path.splitext(file_path)[1].lower()
|
|
194
194
|
if file_extension not in ALLOWED_AUDIO_EXTENSIONS:
|
|
195
|
-
raise
|
|
195
|
+
raise InvalidError(f"Invalid file type. Supported formats are: {ALLOWED_AUDIO_EXTENSIONS}")
|
|
196
196
|
|
|
197
197
|
url = f"{API_BASE_URL}/lightning-large/add_voice"
|
|
198
198
|
payload = {'displayName': display_name}
|
|
@@ -206,8 +206,8 @@ class WavesClient:
|
|
|
206
206
|
response = requests.post(url, headers=headers, data=payload, files=files)
|
|
207
207
|
if response.status_code != 200:
|
|
208
208
|
raise APIError(f"Failed to add voice: {response.text}. For more information, visit https://waves.smallest.ai/")
|
|
209
|
-
|
|
210
|
-
return
|
|
209
|
+
|
|
210
|
+
return response.json()
|
|
211
211
|
|
|
212
212
|
|
|
213
213
|
def delete_voice(self, voice_id: str) -> str:
|
|
@@ -234,4 +234,41 @@ class WavesClient:
|
|
|
234
234
|
if response.status_code != 200:
|
|
235
235
|
raise APIError(f"Failed to delete voice: {response.text}. For more information, visit https://waves.smallest.ai/")
|
|
236
236
|
|
|
237
|
-
return
|
|
237
|
+
return response.json()
|
|
238
|
+
|
|
239
|
+
def transcribe(
|
|
240
|
+
self,
|
|
241
|
+
file_path: str,
|
|
242
|
+
language: Optional[str] = "en",
|
|
243
|
+
word_timestamps: Optional[bool] = False,
|
|
244
|
+
age_detection: Optional[bool] = False,
|
|
245
|
+
gender_detection: Optional[bool] = False,
|
|
246
|
+
emotion_detection: Optional[bool] = False,
|
|
247
|
+
model: Optional[str] = "lightning"
|
|
248
|
+
) -> dict:
|
|
249
|
+
validate_asr_input(file_path, model, language)
|
|
250
|
+
|
|
251
|
+
url = f"{API_BASE_URL}/speech-to-text"
|
|
252
|
+
headers = {
|
|
253
|
+
'Authorization': f"Bearer {self.api_key}",
|
|
254
|
+
}
|
|
255
|
+
payload = {
|
|
256
|
+
'model': model,
|
|
257
|
+
'language': language,
|
|
258
|
+
'word_timestamps': str(bool(word_timestamps)).lower(),
|
|
259
|
+
'age_detection': str(bool(age_detection)).lower(),
|
|
260
|
+
'gender_detection': str(bool(gender_detection)).lower(),
|
|
261
|
+
'emotion_detection': str(bool(emotion_detection)).lower()
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
file_extension = os.path.splitext(file_path)[1].lower()
|
|
265
|
+
content_type = f"audio/{file_extension[1:]}" if file_extension else "application/octet-stream"
|
|
266
|
+
|
|
267
|
+
with open(file_path, 'rb') as f:
|
|
268
|
+
files = {'file': (os.path.basename(file_path), f, content_type)}
|
|
269
|
+
response = requests.post(url, headers=headers, files=files, data=payload)
|
|
270
|
+
|
|
271
|
+
if response.status_code != 200:
|
|
272
|
+
raise APIError(f"Failed to transcribe audio: {response.text}. For more information, visit https://waves-docs.smallest.ai/v4.0.0/content/api-references/asr-post-api")
|
|
273
|
+
|
|
274
|
+
return response.json()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: smallestai
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.1.0
|
|
4
4
|
Summary: Official Python client for the Smallest AI API
|
|
5
5
|
Author-email: Smallest <support@smallest.ai>
|
|
6
6
|
License: MIT
|
|
@@ -142,7 +142,7 @@ def main():
|
|
|
142
142
|
"similarity": 0,
|
|
143
143
|
"enhancement": 1
|
|
144
144
|
},
|
|
145
|
-
"slmModel": "electron
|
|
145
|
+
"slmModel": "electron",
|
|
146
146
|
}
|
|
147
147
|
).data
|
|
148
148
|
|