audiopod 1.4.0__py3-none-any.whl → 2.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.
@@ -1,168 +0,0 @@
1
- """
2
- Stem Extraction Service - Audio stem separation
3
- """
4
-
5
- from typing import List, Optional, Dict, Any
6
- from .base import BaseService
7
- from ..exceptions import ValidationError
8
-
9
-
10
- class StemExtractionService(BaseService):
11
- """
12
- Service for audio stem separation.
13
-
14
- Example:
15
- ```python
16
- from audiopod import Client
17
-
18
- client = Client()
19
-
20
- # Extract all stems
21
- job = client.stem_extraction.extract_stems(
22
- audio_file="song.mp3",
23
- stem_types=["vocals", "drums", "bass", "other"],
24
- wait_for_completion=True
25
- )
26
-
27
- # Download stems
28
- for stem_name, url in job["download_urls"].items():
29
- print(f"{stem_name}: {url}")
30
- ```
31
- """
32
-
33
- def extract_stems(
34
- self,
35
- audio_file: Optional[str] = None,
36
- url: Optional[str] = None,
37
- stem_types: Optional[List[str]] = None,
38
- model_name: str = "htdemucs",
39
- two_stems_mode: Optional[str] = None,
40
- wait_for_completion: bool = False,
41
- timeout: int = 900,
42
- ) -> Dict[str, Any]:
43
- """
44
- Extract stems from audio.
45
-
46
- Args:
47
- audio_file: Path to local audio file
48
- url: URL of audio file (alternative to audio_file)
49
- stem_types: Stems to extract (e.g., ["vocals", "drums", "bass", "other"])
50
- model_name: Model to use ("htdemucs" or "htdemucs_6s")
51
- two_stems_mode: Two-stem mode ("vocals", "drums", or "bass")
52
- wait_for_completion: Wait for job to complete
53
- timeout: Max wait time in seconds
54
-
55
- Returns:
56
- Job dict with id, status, download_urls (when completed)
57
- """
58
- if not audio_file and not url:
59
- raise ValidationError("Provide audio_file or url")
60
-
61
- if audio_file and url:
62
- raise ValidationError("Provide audio_file or url, not both")
63
-
64
- if stem_types is None:
65
- stem_types = (
66
- ["vocals", "drums", "bass", "other", "piano", "guitar"]
67
- if model_name == "htdemucs_6s"
68
- else ["vocals", "drums", "bass", "other"]
69
- )
70
-
71
- data = {"stem_types": str(stem_types), "model_name": model_name}
72
-
73
- if url:
74
- data["url"] = url
75
-
76
- if two_stems_mode:
77
- data["two_stems_mode"] = two_stems_mode
78
-
79
- files = self._prepare_file_upload(audio_file, "file") if audio_file else None
80
-
81
- if self.async_mode:
82
- return self._async_extract_stems(data, files, wait_for_completion, timeout)
83
-
84
- response = self.client.request(
85
- "POST", "/api/v1/stem-extraction/extract", data=data, files=files
86
- )
87
-
88
- if wait_for_completion:
89
- return self._wait_for_stem_job(response["id"], timeout)
90
-
91
- return response
92
-
93
- async def _async_extract_stems(
94
- self,
95
- data: Dict[str, Any],
96
- files: Optional[Dict[str, Any]],
97
- wait_for_completion: bool,
98
- timeout: int,
99
- ) -> Dict[str, Any]:
100
- response = await self.client.request(
101
- "POST", "/api/v1/stem-extraction/extract", data=data, files=files
102
- )
103
- if wait_for_completion:
104
- return await self._async_wait_for_stem_job(response["id"], timeout)
105
- return response
106
-
107
- def get_job(self, job_id: int) -> Dict[str, Any]:
108
- """Get stem extraction job status."""
109
- if self.async_mode:
110
- return self._async_get_job(job_id)
111
- return self.client.request("GET", f"/api/v1/stem-extraction/status/{job_id}")
112
-
113
- async def _async_get_job(self, job_id: int) -> Dict[str, Any]:
114
- return await self.client.request("GET", f"/api/v1/stem-extraction/status/{job_id}")
115
-
116
- def list_jobs(self, skip: int = 0, limit: int = 50) -> List[Dict[str, Any]]:
117
- """List stem extraction jobs."""
118
- if self.async_mode:
119
- return self._async_list_jobs(skip, limit)
120
- return self.client.request(
121
- "GET", "/api/v1/stem-extraction/jobs", params={"skip": skip, "limit": limit}
122
- )
123
-
124
- async def _async_list_jobs(self, skip: int, limit: int) -> List[Dict[str, Any]]:
125
- return await self.client.request(
126
- "GET", "/api/v1/stem-extraction/jobs", params={"skip": skip, "limit": limit}
127
- )
128
-
129
- def delete_job(self, job_id: int) -> Dict[str, str]:
130
- """Delete a stem extraction job."""
131
- if self.async_mode:
132
- return self._async_delete_job(job_id)
133
- return self.client.request("DELETE", f"/api/v1/stem-extraction/jobs/{job_id}")
134
-
135
- async def _async_delete_job(self, job_id: int) -> Dict[str, str]:
136
- return await self.client.request("DELETE", f"/api/v1/stem-extraction/jobs/{job_id}")
137
-
138
- def _wait_for_stem_job(self, job_id: int, timeout: int = 900) -> Dict[str, Any]:
139
- """Wait for stem job completion."""
140
- import time
141
-
142
- start = time.time()
143
- while time.time() - start < timeout:
144
- job = self.get_job(job_id)
145
- status = job.get("status", "").upper()
146
- if status == "COMPLETED":
147
- return job
148
- elif status in ["FAILED", "ERROR"]:
149
- raise Exception(f"Job failed: {job.get('error_message', 'Unknown')}")
150
- time.sleep(5)
151
- raise TimeoutError(f"Job {job_id} timed out after {timeout}s")
152
-
153
- async def _async_wait_for_stem_job(self, job_id: int, timeout: int = 900) -> Dict[str, Any]:
154
- """Async wait for stem job completion."""
155
- import asyncio
156
- import time
157
-
158
- start = time.time()
159
- while time.time() - start < timeout:
160
- job = await self.get_job(job_id)
161
- status = job.get("status", "").upper()
162
- if status == "COMPLETED":
163
- return job
164
- elif status in ["FAILED", "ERROR"]:
165
- raise Exception(f"Job failed: {job.get('error_message', 'Unknown')}")
166
- await asyncio.sleep(5)
167
- raise TimeoutError(f"Job {job_id} timed out after {timeout}s")
168
-
@@ -1,187 +0,0 @@
1
- """
2
- Transcription Service - Speech-to-text
3
-
4
- API Routes:
5
- - POST /api/v1/transcription/transcribe - Transcribe from URL
6
- - POST /api/v1/transcription/transcribe-upload - Transcribe from file upload
7
- - GET /api/v1/transcription/jobs/{id} - Get job details
8
- - GET /api/v1/transcription/jobs - List jobs
9
- - DELETE /api/v1/transcription/jobs/{id} - Delete job
10
- """
11
-
12
- from typing import Optional, Dict, Any, List
13
- from .base import BaseService
14
-
15
-
16
- class TranscriptionService(BaseService):
17
- """Service for speech-to-text transcription."""
18
-
19
- def transcribe(
20
- self,
21
- audio_file: Optional[str] = None,
22
- url: Optional[str] = None,
23
- language: Optional[str] = None,
24
- speaker_diarization: bool = False,
25
- wait_for_completion: bool = False,
26
- timeout: int = 600,
27
- ) -> Dict[str, Any]:
28
- """
29
- Transcribe audio to text.
30
-
31
- Args:
32
- audio_file: Path to local audio file
33
- url: URL of audio file (or list of URLs)
34
- language: Language code (auto-detected if not provided)
35
- speaker_diarization: Enable speaker separation
36
- wait_for_completion: Wait for completion
37
- timeout: Max wait time in seconds
38
-
39
- Returns:
40
- Job dict with transcript when completed
41
- """
42
- if audio_file:
43
- # File upload endpoint
44
- data = {
45
- "enable_speaker_diarization": speaker_diarization,
46
- }
47
- if language:
48
- data["language"] = language
49
-
50
- files = self._prepare_file_upload(audio_file, "files")
51
-
52
- if self.async_mode:
53
- return self._async_transcribe_upload(data, files, wait_for_completion, timeout)
54
-
55
- response = self.client.request(
56
- "POST", "/api/v1/transcription/transcribe-upload", data=data, files=files
57
- )
58
- else:
59
- # URL-based endpoint
60
- data = {
61
- "source_urls": [url] if isinstance(url, str) else url,
62
- "enable_speaker_diarization": speaker_diarization,
63
- }
64
- if language:
65
- data["language"] = language
66
-
67
- if self.async_mode:
68
- return self._async_transcribe(data, wait_for_completion, timeout)
69
-
70
- response = self.client.request(
71
- "POST", "/api/v1/transcription/transcribe", json_data=data
72
- )
73
-
74
- if wait_for_completion:
75
- job_id = response.get("id") or response.get("job_id")
76
- return self._wait_for_transcription(job_id, timeout)
77
- return response
78
-
79
- async def _async_transcribe(
80
- self, data: Dict, wait_for_completion: bool, timeout: int
81
- ) -> Dict[str, Any]:
82
- response = await self.client.request(
83
- "POST", "/api/v1/transcription/transcribe", json_data=data
84
- )
85
- if wait_for_completion:
86
- job_id = response.get("id") or response.get("job_id")
87
- return await self._async_wait_for_transcription(job_id, timeout)
88
- return response
89
-
90
- async def _async_transcribe_upload(
91
- self, data: Dict, files: Dict, wait_for_completion: bool, timeout: int
92
- ) -> Dict[str, Any]:
93
- response = await self.client.request(
94
- "POST", "/api/v1/transcription/transcribe-upload", data=data, files=files
95
- )
96
- if wait_for_completion:
97
- job_id = response.get("id") or response.get("job_id")
98
- return await self._async_wait_for_transcription(job_id, timeout)
99
- return response
100
-
101
- def get_job(self, job_id: int) -> Dict[str, Any]:
102
- """Get transcription job details and status."""
103
- if self.async_mode:
104
- return self._async_get_job(job_id)
105
- return self.client.request("GET", f"/api/v1/transcription/jobs/{job_id}")
106
-
107
- async def _async_get_job(self, job_id: int) -> Dict[str, Any]:
108
- return await self.client.request("GET", f"/api/v1/transcription/jobs/{job_id}")
109
-
110
- def list_jobs(self, skip: int = 0, limit: int = 50) -> List[Dict[str, Any]]:
111
- """List transcription jobs."""
112
- if self.async_mode:
113
- return self._async_list_jobs(skip, limit)
114
- return self.client.request(
115
- "GET", "/api/v1/transcription/jobs", params={"skip": skip, "limit": limit}
116
- )
117
-
118
- async def _async_list_jobs(self, skip: int, limit: int) -> List[Dict[str, Any]]:
119
- return await self.client.request(
120
- "GET", "/api/v1/transcription/jobs", params={"skip": skip, "limit": limit}
121
- )
122
-
123
- def delete_job(self, job_id: int) -> Dict[str, str]:
124
- """Delete a transcription job."""
125
- if self.async_mode:
126
- return self._async_delete_job(job_id)
127
- return self.client.request("DELETE", f"/api/v1/transcription/jobs/{job_id}")
128
-
129
- async def _async_delete_job(self, job_id: int) -> Dict[str, str]:
130
- return await self.client.request("DELETE", f"/api/v1/transcription/jobs/{job_id}")
131
-
132
- def get_transcript(self, job_id: int, format: str = "json") -> Any:
133
- """
134
- Get transcript content.
135
-
136
- Args:
137
- job_id: Job ID
138
- format: Output format - 'json', 'txt', 'srt', 'vtt'
139
- """
140
- if self.async_mode:
141
- return self._async_get_transcript(job_id, format)
142
- return self.client.request(
143
- "GET", f"/api/v1/transcription/jobs/{job_id}/transcript", params={"format": format}
144
- )
145
-
146
- async def _async_get_transcript(self, job_id: int, format: str) -> Any:
147
- return await self.client.request(
148
- "GET", f"/api/v1/transcription/jobs/{job_id}/transcript", params={"format": format}
149
- )
150
-
151
- def _wait_for_transcription(self, job_id: int, timeout: int) -> Dict[str, Any]:
152
- """Wait for transcription job completion."""
153
- import time
154
- start_time = time.time()
155
-
156
- while time.time() - start_time < timeout:
157
- job = self.get_job(job_id)
158
- status = job.get("status", "").upper()
159
-
160
- if status == "COMPLETED":
161
- return job
162
- elif status in ("FAILED", "ERROR", "CANCELLED"):
163
- raise Exception(f"Transcription failed: {job.get('error_message', 'Unknown error')}")
164
-
165
- time.sleep(3)
166
-
167
- raise TimeoutError(f"Transcription {job_id} did not complete within {timeout} seconds")
168
-
169
- async def _async_wait_for_transcription(self, job_id: int, timeout: int) -> Dict[str, Any]:
170
- """Async wait for transcription job completion."""
171
- import asyncio
172
- import time
173
- start_time = time.time()
174
-
175
- while time.time() - start_time < timeout:
176
- job = await self.get_job(job_id)
177
- status = job.get("status", "").upper()
178
-
179
- if status == "COMPLETED":
180
- return job
181
- elif status in ("FAILED", "ERROR", "CANCELLED"):
182
- raise Exception(f"Transcription failed: {job.get('error_message', 'Unknown error')}")
183
-
184
- await asyncio.sleep(3)
185
-
186
- raise TimeoutError(f"Transcription {job_id} did not complete within {timeout} seconds")
187
-
@@ -1,135 +0,0 @@
1
- """
2
- Translation Service - Audio/speech translation
3
-
4
- API Routes:
5
- - POST /api/v1/translation/translate/speech - Translate speech
6
- - GET /api/v1/translation/translations/{id} - Get translation job
7
- - GET /api/v1/translation/translations - List translations
8
- - DELETE /api/v1/translation/translations/{id} - Delete translation
9
- """
10
-
11
- from typing import Optional, Dict, Any, List
12
- from .base import BaseService
13
-
14
-
15
- class TranslationService(BaseService):
16
- """Service for audio translation."""
17
-
18
- def translate(
19
- self,
20
- audio_file: Optional[str] = None,
21
- url: Optional[str] = None,
22
- target_language: str = "en",
23
- source_language: Optional[str] = None,
24
- wait_for_completion: bool = False,
25
- timeout: int = 900,
26
- ) -> Dict[str, Any]:
27
- """
28
- Translate audio to another language.
29
-
30
- Args:
31
- audio_file: Path to local audio file
32
- url: URL of audio file
33
- target_language: Target language code
34
- source_language: Source language (auto-detected if not provided)
35
- wait_for_completion: Wait for completion
36
- timeout: Max wait time in seconds
37
-
38
- Returns:
39
- Job dict with translated audio URL when completed
40
- """
41
- data = {"target_language": target_language}
42
- if source_language:
43
- data["source_language"] = source_language
44
- if url:
45
- data["url"] = url
46
-
47
- files = self._prepare_file_upload(audio_file, "file") if audio_file else None
48
-
49
- if self.async_mode:
50
- return self._async_translate(data, files, wait_for_completion, timeout)
51
-
52
- response = self.client.request("POST", "/api/v1/translation/translate/speech", data=data, files=files)
53
-
54
- if wait_for_completion:
55
- job_id = response.get("id") or response.get("job_id")
56
- return self._wait_for_translation(job_id, timeout)
57
- return response
58
-
59
- async def _async_translate(
60
- self, data: Dict, files: Optional[Dict], wait_for_completion: bool, timeout: int
61
- ) -> Dict[str, Any]:
62
- response = await self.client.request("POST", "/api/v1/translation/translate/speech", data=data, files=files)
63
- if wait_for_completion:
64
- job_id = response.get("id") or response.get("job_id")
65
- return await self._async_wait_for_translation(job_id, timeout)
66
- return response
67
-
68
- def get_job(self, job_id: int) -> Dict[str, Any]:
69
- """Get translation job details and status."""
70
- if self.async_mode:
71
- return self._async_get_job(job_id)
72
- return self.client.request("GET", f"/api/v1/translation/translations/{job_id}")
73
-
74
- async def _async_get_job(self, job_id: int) -> Dict[str, Any]:
75
- return await self.client.request("GET", f"/api/v1/translation/translations/{job_id}")
76
-
77
- def list_jobs(self, skip: int = 0, limit: int = 50) -> List[Dict[str, Any]]:
78
- """List translation jobs."""
79
- if self.async_mode:
80
- return self._async_list_jobs(skip, limit)
81
- return self.client.request(
82
- "GET", "/api/v1/translation/translations", params={"skip": skip, "limit": limit}
83
- )
84
-
85
- async def _async_list_jobs(self, skip: int, limit: int) -> List[Dict[str, Any]]:
86
- return await self.client.request(
87
- "GET", "/api/v1/translation/translations", params={"skip": skip, "limit": limit}
88
- )
89
-
90
- def delete_job(self, job_id: int) -> Dict[str, str]:
91
- """Delete a translation job."""
92
- if self.async_mode:
93
- return self._async_delete_job(job_id)
94
- return self.client.request("DELETE", f"/api/v1/translation/translations/{job_id}")
95
-
96
- async def _async_delete_job(self, job_id: int) -> Dict[str, str]:
97
- return await self.client.request("DELETE", f"/api/v1/translation/translations/{job_id}")
98
-
99
- def _wait_for_translation(self, job_id: int, timeout: int) -> Dict[str, Any]:
100
- """Wait for translation job completion."""
101
- import time
102
- start_time = time.time()
103
-
104
- while time.time() - start_time < timeout:
105
- job = self.get_job(job_id)
106
- status = job.get("status", "").upper()
107
-
108
- if status == "COMPLETED":
109
- return job
110
- elif status in ("FAILED", "ERROR"):
111
- raise Exception(f"Translation failed: {job.get('error_message', 'Unknown error')}")
112
-
113
- time.sleep(5)
114
-
115
- raise TimeoutError(f"Translation {job_id} did not complete within {timeout} seconds")
116
-
117
- async def _async_wait_for_translation(self, job_id: int, timeout: int) -> Dict[str, Any]:
118
- """Async wait for translation job completion."""
119
- import asyncio
120
- import time
121
- start_time = time.time()
122
-
123
- while time.time() - start_time < timeout:
124
- job = await self.get_job(job_id)
125
- status = job.get("status", "").upper()
126
-
127
- if status == "COMPLETED":
128
- return job
129
- elif status in ("FAILED", "ERROR"):
130
- raise Exception(f"Translation failed: {job.get('error_message', 'Unknown error')}")
131
-
132
- await asyncio.sleep(5)
133
-
134
- raise TimeoutError(f"Translation {job_id} did not complete within {timeout} seconds")
135
-
@@ -1,187 +0,0 @@
1
- """
2
- Voice Service - Voice cloning and text-to-speech
3
-
4
- API Routes:
5
- - GET /api/v1/voice/voice-profiles - List all voices
6
- - GET /api/v1/voice/voices/{id}/status - Get voice details
7
- - POST /api/v1/voice/voice-profiles - Create voice clone
8
- - DELETE /api/v1/voice/voices/{id} - Delete voice
9
- - POST /api/v1/voice/voices/{id}/generate - Generate TTS
10
- - GET /api/v1/voice/tts-jobs/{id}/status - Get TTS job status
11
- """
12
-
13
- from typing import Optional, Dict, Any, List, Union
14
- from .base import BaseService
15
-
16
-
17
- class VoiceService(BaseService):
18
- """Service for voice cloning and text-to-speech."""
19
-
20
- def list_voices(
21
- self,
22
- skip: int = 0,
23
- limit: int = 100,
24
- include_public: bool = True,
25
- ) -> List[Dict[str, Any]]:
26
- """List available voices (both custom and public)."""
27
- params = {
28
- "skip": skip,
29
- "limit": limit,
30
- "include_public": str(include_public).lower(),
31
- }
32
- if self.async_mode:
33
- return self._async_list_voices(params)
34
- return self.client.request("GET", "/api/v1/voice/voice-profiles", params=params)
35
-
36
- async def _async_list_voices(self, params: Dict) -> List[Dict[str, Any]]:
37
- return await self.client.request("GET", "/api/v1/voice/voice-profiles", params=params)
38
-
39
- def get_voice(self, voice_id: Union[int, str]) -> Dict[str, Any]:
40
- """Get voice details by ID or UUID."""
41
- if self.async_mode:
42
- return self._async_get_voice(voice_id)
43
- return self.client.request("GET", f"/api/v1/voice/voices/{voice_id}/status")
44
-
45
- async def _async_get_voice(self, voice_id: Union[int, str]) -> Dict[str, Any]:
46
- return await self.client.request("GET", f"/api/v1/voice/voices/{voice_id}/status")
47
-
48
- def create_voice(
49
- self,
50
- name: str,
51
- audio_file: str,
52
- description: Optional[str] = None,
53
- ) -> Dict[str, Any]:
54
- """Create a new voice clone from an audio file."""
55
- files = self._prepare_file_upload(audio_file, "file")
56
- data = {"name": name}
57
- if description:
58
- data["description"] = description
59
-
60
- if self.async_mode:
61
- return self._async_create_voice(data, files)
62
- return self.client.request("POST", "/api/v1/voice/voice-profiles", data=data, files=files)
63
-
64
- async def _async_create_voice(self, data: Dict, files: Dict) -> Dict[str, Any]:
65
- return await self.client.request("POST", "/api/v1/voice/voice-profiles", data=data, files=files)
66
-
67
- def delete_voice(self, voice_id: Union[int, str]) -> Dict[str, str]:
68
- """Delete a voice by ID or UUID."""
69
- if self.async_mode:
70
- return self._async_delete_voice(voice_id)
71
- return self.client.request("DELETE", f"/api/v1/voice/voices/{voice_id}")
72
-
73
- async def _async_delete_voice(self, voice_id: Union[int, str]) -> Dict[str, str]:
74
- return await self.client.request("DELETE", f"/api/v1/voice/voices/{voice_id}")
75
-
76
- def generate_speech(
77
- self,
78
- voice_id: Union[int, str],
79
- text: str,
80
- speed: float = 1.0,
81
- language: str = "en",
82
- audio_format: str = "mp3",
83
- wait_for_completion: bool = False,
84
- timeout: int = 300,
85
- ) -> Dict[str, Any]:
86
- """
87
- Generate speech from text using a voice.
88
-
89
- Args:
90
- voice_id: Voice ID (int) or UUID (str) to use for generation
91
- text: Text to convert to speech
92
- speed: Speech speed (0.25 to 4.0, default 1.0)
93
- language: Language code (default "en")
94
- audio_format: Output format - mp3, wav, ogg (default "mp3")
95
- wait_for_completion: If True, poll until job completes
96
- timeout: Max seconds to wait for completion
97
-
98
- Returns:
99
- Job info dict with job_id, status, etc.
100
- If wait_for_completion=True, includes output_url when done.
101
- """
102
- data = {
103
- "input_text": text,
104
- "speed": speed,
105
- "language": language,
106
- "audio_format": audio_format,
107
- }
108
-
109
- if self.async_mode:
110
- return self._async_generate_speech(voice_id, data, wait_for_completion, timeout)
111
-
112
- response = self.client.request(
113
- "POST",
114
- f"/api/v1/voice/voices/{voice_id}/generate",
115
- data=data,
116
- )
117
-
118
- if wait_for_completion:
119
- job_id = response.get("job_id") or response.get("id")
120
- return self._wait_for_job_completion(job_id, timeout)
121
- return response
122
-
123
- async def _async_generate_speech(
124
- self, voice_id: Union[int, str], data: Dict, wait_for_completion: bool, timeout: int
125
- ) -> Dict[str, Any]:
126
- response = await self.client.request(
127
- "POST",
128
- f"/api/v1/voice/voices/{voice_id}/generate",
129
- data=data,
130
- )
131
- if wait_for_completion:
132
- job_id = response.get("job_id") or response.get("id")
133
- return await self._async_wait_for_job_completion(job_id, timeout)
134
- return response
135
-
136
- def get_job_status(self, job_id: int) -> Dict[str, Any]:
137
- """
138
- Get TTS job status.
139
-
140
- Args:
141
- job_id: The job ID returned from generate_speech
142
-
143
- Returns:
144
- Job status dict with status, progress, output_url (when completed), etc.
145
- """
146
- if self.async_mode:
147
- return self._async_get_job_status(job_id)
148
- return self.client.request("GET", f"/api/v1/voice/tts-jobs/{job_id}/status")
149
-
150
- async def _async_get_job_status(self, job_id: int) -> Dict[str, Any]:
151
- return await self.client.request("GET", f"/api/v1/voice/tts-jobs/{job_id}/status")
152
-
153
- def _wait_for_job_completion(self, job_id: int, timeout: int) -> Dict[str, Any]:
154
- """Poll job status until completion or timeout."""
155
- import time
156
- start_time = time.time()
157
-
158
- while time.time() - start_time < timeout:
159
- status = self.get_job_status(job_id)
160
-
161
- if status.get("status") in ("completed", "COMPLETED"):
162
- return status
163
- elif status.get("status") in ("failed", "FAILED", "error", "ERROR"):
164
- raise Exception(f"Job failed: {status.get('error_message', 'Unknown error')}")
165
-
166
- time.sleep(2)
167
-
168
- raise TimeoutError(f"Job {job_id} did not complete within {timeout} seconds")
169
-
170
- async def _async_wait_for_job_completion(self, job_id: int, timeout: int) -> Dict[str, Any]:
171
- """Async poll job status until completion or timeout."""
172
- import asyncio
173
- import time
174
- start_time = time.time()
175
-
176
- while time.time() - start_time < timeout:
177
- status = await self.get_job_status(job_id)
178
-
179
- if status.get("status") in ("completed", "COMPLETED"):
180
- return status
181
- elif status.get("status") in ("failed", "FAILED", "error", "ERROR"):
182
- raise Exception(f"Job failed: {status.get('error_message', 'Unknown error')}")
183
-
184
- await asyncio.sleep(2)
185
-
186
- raise TimeoutError(f"Job {job_id} did not complete within {timeout} seconds")
187
-