typecast-python 0.3.6__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.
Files changed (19) hide show
  1. {typecast_python-0.3.6 → typecast_python-0.3.7}/PKG-INFO +1 -1
  2. {typecast_python-0.3.6 → typecast_python-0.3.7}/pyproject.toml +1 -1
  3. typecast_python-0.3.7/src/typecast/_user_agent.py +70 -0
  4. {typecast_python-0.3.6 → typecast_python-0.3.7}/src/typecast/async_client.py +7 -2
  5. {typecast_python-0.3.6 → typecast_python-0.3.7}/src/typecast/client.py +10 -2
  6. {typecast_python-0.3.6 → typecast_python-0.3.7}/.gitignore +0 -0
  7. {typecast_python-0.3.6 → typecast_python-0.3.7}/LICENSE +0 -0
  8. {typecast_python-0.3.6 → typecast_python-0.3.7}/README.md +0 -0
  9. {typecast_python-0.3.6 → typecast_python-0.3.7}/src/typecast/__init__.py +0 -0
  10. {typecast_python-0.3.6 → typecast_python-0.3.7}/src/typecast/_voice_clone.py +0 -0
  11. {typecast_python-0.3.6 → typecast_python-0.3.7}/src/typecast/composer.py +0 -0
  12. {typecast_python-0.3.6 → typecast_python-0.3.7}/src/typecast/conf.py +0 -0
  13. {typecast_python-0.3.6 → typecast_python-0.3.7}/src/typecast/exceptions.py +0 -0
  14. {typecast_python-0.3.6 → typecast_python-0.3.7}/src/typecast/models/__init__.py +0 -0
  15. {typecast_python-0.3.6 → typecast_python-0.3.7}/src/typecast/models/error.py +0 -0
  16. {typecast_python-0.3.6 → typecast_python-0.3.7}/src/typecast/models/subscription.py +0 -0
  17. {typecast_python-0.3.6 → typecast_python-0.3.7}/src/typecast/models/tts.py +0 -0
  18. {typecast_python-0.3.6 → typecast_python-0.3.7}/src/typecast/models/voices.py +0 -0
  19. {typecast_python-0.3.6 → 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.6
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.6"
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)
@@ -203,7 +204,11 @@ class AsyncTypecast:
203
204
  NotFoundError, UnprocessableEntityError, RateLimitError,
204
205
  InternalServerError, TypecastError: depending on response status.
205
206
  """
206
- if not isinstance(chunk_size, int) or isinstance(chunk_size, bool) or chunk_size < 1:
207
+ if (
208
+ not isinstance(chunk_size, int)
209
+ or isinstance(chunk_size, bool)
210
+ or chunk_size < 1
211
+ ):
207
212
  raise ValueError("chunk_size must be a positive integer")
208
213
  if not self.session:
209
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 = {"Content-Type": "application/json"}
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)
@@ -236,7 +240,11 @@ class Typecast:
236
240
  NotFoundError, UnprocessableEntityError, RateLimitError,
237
241
  InternalServerError, TypecastError: depending on response status.
238
242
  """
239
- if not isinstance(chunk_size, int) or isinstance(chunk_size, bool) or chunk_size < 1:
243
+ if (
244
+ not isinstance(chunk_size, int)
245
+ or isinstance(chunk_size, bool)
246
+ or chunk_size < 1
247
+ ):
240
248
  raise ValueError("chunk_size must be a positive integer")
241
249
  endpoint = "/v1/text-to-speech/stream"
242
250
  response = self.session.post(
File without changes