typecast-python 0.3.5__tar.gz → 0.3.7__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.
- {typecast_python-0.3.5 → typecast_python-0.3.7}/PKG-INFO +1 -1
- {typecast_python-0.3.5 → typecast_python-0.3.7}/pyproject.toml +1 -1
- typecast_python-0.3.7/src/typecast/_user_agent.py +70 -0
- {typecast_python-0.3.5 → typecast_python-0.3.7}/src/typecast/async_client.py +8 -4
- {typecast_python-0.3.5 → typecast_python-0.3.7}/src/typecast/client.py +11 -4
- {typecast_python-0.3.5 → typecast_python-0.3.7}/src/typecast/models/tts.py +9 -4
- {typecast_python-0.3.5 → typecast_python-0.3.7}/.gitignore +0 -0
- {typecast_python-0.3.5 → typecast_python-0.3.7}/LICENSE +0 -0
- {typecast_python-0.3.5 → typecast_python-0.3.7}/README.md +0 -0
- {typecast_python-0.3.5 → typecast_python-0.3.7}/src/typecast/__init__.py +0 -0
- {typecast_python-0.3.5 → typecast_python-0.3.7}/src/typecast/_voice_clone.py +0 -0
- {typecast_python-0.3.5 → typecast_python-0.3.7}/src/typecast/composer.py +0 -0
- {typecast_python-0.3.5 → typecast_python-0.3.7}/src/typecast/conf.py +0 -0
- {typecast_python-0.3.5 → typecast_python-0.3.7}/src/typecast/exceptions.py +0 -0
- {typecast_python-0.3.5 → typecast_python-0.3.7}/src/typecast/models/__init__.py +0 -0
- {typecast_python-0.3.5 → typecast_python-0.3.7}/src/typecast/models/error.py +0 -0
- {typecast_python-0.3.5 → typecast_python-0.3.7}/src/typecast/models/subscription.py +0 -0
- {typecast_python-0.3.5 → typecast_python-0.3.7}/src/typecast/models/voices.py +0 -0
- {typecast_python-0.3.5 → typecast_python-0.3.7}/src/typecast/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: typecast-python
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
4
4
|
Summary: Official Typecast Python SDK - Convert text to lifelike speech using AI-powered voices
|
|
5
5
|
Project-URL: Homepage, https://typecast.ai
|
|
6
6
|
Project-URL: Documentation, https://typecast.ai/docs/overview
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "typecast-python"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.7"
|
|
8
8
|
description = "Official Typecast Python SDK - Convert text to lifelike speech using AI-powered voices"
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "Neosapience", email = "help@typecast.ai"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import platform
|
|
2
|
+
import sys
|
|
3
|
+
from importlib import metadata
|
|
4
|
+
|
|
5
|
+
import aiohttp
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
from . import conf
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _package_version(package_name: str) -> str:
|
|
12
|
+
try:
|
|
13
|
+
return metadata.version(package_name)
|
|
14
|
+
except metadata.PackageNotFoundError:
|
|
15
|
+
return "dev"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _os_name() -> str:
|
|
19
|
+
system = platform.system().lower()
|
|
20
|
+
if system == "darwin":
|
|
21
|
+
return "macos"
|
|
22
|
+
if system.startswith("windows"):
|
|
23
|
+
return "windows"
|
|
24
|
+
return system or "unknown"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _arch_name() -> str:
|
|
28
|
+
machine = platform.machine().lower()
|
|
29
|
+
if machine in {"x86_64", "amd64"}:
|
|
30
|
+
return "x64"
|
|
31
|
+
if machine in {"aarch64", "arm64"}:
|
|
32
|
+
return "arm64"
|
|
33
|
+
return machine or "unknown"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def build_user_agent(
|
|
37
|
+
*,
|
|
38
|
+
mode: str,
|
|
39
|
+
http_library: str,
|
|
40
|
+
host: str,
|
|
41
|
+
transport: str = "rest",
|
|
42
|
+
) -> str:
|
|
43
|
+
sdk_version = _package_version("typecast-python")
|
|
44
|
+
base = "default" if conf.is_default_host(host) else "custom"
|
|
45
|
+
return (
|
|
46
|
+
f"typecast-python/{sdk_version} "
|
|
47
|
+
f"Python/{sys.version_info.major}.{sys.version_info.minor} "
|
|
48
|
+
f"{platform.python_implementation()}/{platform.python_version()} "
|
|
49
|
+
f"{http_library} "
|
|
50
|
+
f"(mode={mode}; base={base}; transport={transport}; "
|
|
51
|
+
f"os={_os_name()}; arch={_arch_name()}; sdk_env=python; platform=server)"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def requests_user_agent(host: str, transport: str = "rest") -> str:
|
|
56
|
+
return build_user_agent(
|
|
57
|
+
mode="sync",
|
|
58
|
+
http_library=f"requests/{requests.__version__}",
|
|
59
|
+
host=host,
|
|
60
|
+
transport=transport,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def aiohttp_user_agent(host: str, transport: str = "rest") -> str:
|
|
65
|
+
return build_user_agent(
|
|
66
|
+
mode="async",
|
|
67
|
+
http_library=f"aiohttp/{aiohttp.__version__}",
|
|
68
|
+
host=host,
|
|
69
|
+
transport=transport,
|
|
70
|
+
)
|
|
@@ -11,6 +11,7 @@ from ._voice_clone import (
|
|
|
11
11
|
validate_clone_inputs,
|
|
12
12
|
validate_custom_voice_id,
|
|
13
13
|
)
|
|
14
|
+
from ._user_agent import aiohttp_user_agent
|
|
14
15
|
from .client import _guess_audio_mime
|
|
15
16
|
from .client import _output_with_inferred_format
|
|
16
17
|
from .client import _validate_output_path
|
|
@@ -81,7 +82,7 @@ class AsyncTypecast:
|
|
|
81
82
|
async def __aenter__(self):
|
|
82
83
|
# Auth header at session scope; per-request Content-Type is set by aiohttp
|
|
83
84
|
# (json= auto-sets application/json, data=FormData() auto-sets multipart).
|
|
84
|
-
headers = {}
|
|
85
|
+
headers = {"User-Agent": aiohttp_user_agent(self.host)}
|
|
85
86
|
if self.api_key:
|
|
86
87
|
headers["X-API-KEY"] = self.api_key
|
|
87
88
|
self.session = aiohttp.ClientSession(headers=headers)
|
|
@@ -191,8 +192,7 @@ class AsyncTypecast:
|
|
|
191
192
|
|
|
192
193
|
Args:
|
|
193
194
|
request: Streaming TTS request. Uses `OutputStream`, which omits
|
|
194
|
-
`volume`
|
|
195
|
-
endpoint).
|
|
195
|
+
`volume` (not supported by the streaming endpoint).
|
|
196
196
|
chunk_size: Maximum bytes returned per yielded chunk.
|
|
197
197
|
|
|
198
198
|
Yields:
|
|
@@ -204,7 +204,11 @@ class AsyncTypecast:
|
|
|
204
204
|
NotFoundError, UnprocessableEntityError, RateLimitError,
|
|
205
205
|
InternalServerError, TypecastError: depending on response status.
|
|
206
206
|
"""
|
|
207
|
-
if
|
|
207
|
+
if (
|
|
208
|
+
not isinstance(chunk_size, int)
|
|
209
|
+
or isinstance(chunk_size, bool)
|
|
210
|
+
or chunk_size < 1
|
|
211
|
+
):
|
|
208
212
|
raise ValueError("chunk_size must be a positive integer")
|
|
209
213
|
if not self.session:
|
|
210
214
|
raise TypecastError("Client session not initialized. Use async with.")
|
|
@@ -10,6 +10,7 @@ from ._voice_clone import (
|
|
|
10
10
|
validate_clone_inputs,
|
|
11
11
|
validate_custom_voice_id,
|
|
12
12
|
)
|
|
13
|
+
from ._user_agent import requests_user_agent
|
|
13
14
|
from .composer import SpeechComposer
|
|
14
15
|
from .exceptions import (
|
|
15
16
|
BadRequestError,
|
|
@@ -111,7 +112,10 @@ class Typecast:
|
|
|
111
112
|
if not self.api_key and conf.is_default_host(self.host):
|
|
112
113
|
raise ValueError("API key is required for the default Typecast API host")
|
|
113
114
|
self.session = requests.Session()
|
|
114
|
-
headers = {
|
|
115
|
+
headers = {
|
|
116
|
+
"Content-Type": "application/json",
|
|
117
|
+
"User-Agent": requests_user_agent(self.host),
|
|
118
|
+
}
|
|
115
119
|
if self.api_key:
|
|
116
120
|
headers["X-API-KEY"] = self.api_key
|
|
117
121
|
self.session.headers.update(headers)
|
|
@@ -225,8 +229,7 @@ class Typecast:
|
|
|
225
229
|
|
|
226
230
|
Args:
|
|
227
231
|
request: Streaming TTS request. Uses `OutputStream`, which omits
|
|
228
|
-
`volume`
|
|
229
|
-
endpoint).
|
|
232
|
+
`volume` (not supported by the streaming endpoint).
|
|
230
233
|
chunk_size: Maximum bytes returned per yielded chunk.
|
|
231
234
|
|
|
232
235
|
Yields:
|
|
@@ -237,7 +240,11 @@ class Typecast:
|
|
|
237
240
|
NotFoundError, UnprocessableEntityError, RateLimitError,
|
|
238
241
|
InternalServerError, TypecastError: depending on response status.
|
|
239
242
|
"""
|
|
240
|
-
if
|
|
243
|
+
if (
|
|
244
|
+
not isinstance(chunk_size, int)
|
|
245
|
+
or isinstance(chunk_size, bool)
|
|
246
|
+
or chunk_size < 1
|
|
247
|
+
):
|
|
241
248
|
raise ValueError("chunk_size must be a positive integer")
|
|
242
249
|
endpoint = "/v1/text-to-speech/stream"
|
|
243
250
|
response = self.session.post(
|
|
@@ -183,9 +183,8 @@ class TTSResponse(BaseModel):
|
|
|
183
183
|
class OutputStream(BaseModel):
|
|
184
184
|
"""Audio output settings for streaming mode.
|
|
185
185
|
|
|
186
|
-
Streaming mode does not support `volume
|
|
187
|
-
|
|
188
|
-
Passing either field raises a validation error so misuse fails fast.
|
|
186
|
+
Streaming mode does not support `volume`, but it supports `target_lufs`
|
|
187
|
+
for absolute loudness normalization.
|
|
189
188
|
"""
|
|
190
189
|
|
|
191
190
|
model_config = ConfigDict(extra="forbid")
|
|
@@ -195,12 +194,18 @@ class OutputStream(BaseModel):
|
|
|
195
194
|
audio_format: Optional[str] = Field(
|
|
196
195
|
default="wav", description="Audio format", examples=["wav", "mp3"]
|
|
197
196
|
)
|
|
197
|
+
target_lufs: Optional[float] = Field(
|
|
198
|
+
default=None,
|
|
199
|
+
ge=-70.0,
|
|
200
|
+
le=0.0,
|
|
201
|
+
description="Target loudness in LUFS for streaming output normalization (-70 to 0).",
|
|
202
|
+
)
|
|
198
203
|
|
|
199
204
|
|
|
200
205
|
class TTSRequestStream(BaseModel):
|
|
201
206
|
"""Request body for `POST /v1/text-to-speech/stream`.
|
|
202
207
|
|
|
203
|
-
Mirrors `TTSRequest` but uses `OutputStream` (no volume
|
|
208
|
+
Mirrors `TTSRequest` but uses `OutputStream` (no volume).
|
|
204
209
|
"""
|
|
205
210
|
|
|
206
211
|
model_config = ConfigDict(json_schema_extra={"exclude_none": True})
|
|
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
|