audiopod 1.1.0__tar.gz → 1.1.1__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 (33) hide show
  1. {audiopod-1.1.0 → audiopod-1.1.1}/CHANGELOG.md +79 -0
  2. {audiopod-1.1.0 → audiopod-1.1.1}/PKG-INFO +13 -5
  3. {audiopod-1.1.0 → audiopod-1.1.1}/README.md +12 -4
  4. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/__init__.py +1 -1
  5. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/models.py +21 -6
  6. audiopod-1.1.1/audiopod/services/translation.py +196 -0
  7. {audiopod-1.1.0 → audiopod-1.1.1}/examples/basic_usage.py +42 -6
  8. {audiopod-1.1.0 → audiopod-1.1.1}/pyproject.toml +1 -1
  9. audiopod-1.1.0/audiopod/services/translation.py +0 -81
  10. {audiopod-1.1.0 → audiopod-1.1.1}/LICENSE +0 -0
  11. {audiopod-1.1.0 → audiopod-1.1.1}/MANIFEST.in +0 -0
  12. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/cli.py +0 -0
  13. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/client.py +0 -0
  14. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/config.py +0 -0
  15. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/exceptions.py +0 -0
  16. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/py.typed +0 -0
  17. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/services/__init__.py +0 -0
  18. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/services/base.py +0 -0
  19. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/services/credits.py +0 -0
  20. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/services/denoiser.py +0 -0
  21. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/services/karaoke.py +0 -0
  22. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/services/music.py +0 -0
  23. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/services/speaker.py +0 -0
  24. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/services/stem_extraction.py +0 -0
  25. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/services/transcription.py +0 -0
  26. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod/services/voice.py +0 -0
  27. {audiopod-1.1.0 → audiopod-1.1.1}/audiopod.egg-info/SOURCES.txt +0 -0
  28. {audiopod-1.1.0 → audiopod-1.1.1}/examples/README.md +0 -0
  29. {audiopod-1.1.0 → audiopod-1.1.1}/requirements.txt +0 -0
  30. {audiopod-1.1.0 → audiopod-1.1.1}/setup.cfg +0 -0
  31. {audiopod-1.1.0 → audiopod-1.1.1}/setup.py +0 -0
  32. {audiopod-1.1.0 → audiopod-1.1.1}/tests/test_end_to_end_integration.py +0 -0
  33. {audiopod-1.1.0 → audiopod-1.1.1}/tests/test_sdk_api_compatibility.py +0 -0
@@ -5,6 +5,85 @@ All notable changes to the AudioPod Python SDK 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
+ ## [1.1.1] - 2024-12-15
9
+
10
+ ### 🔧 Translation Service Fixes
11
+
12
+ This release fixes the translation service to use the proper speech-to-speech translation endpoint and adds enhanced functionality.
13
+
14
+ ### ✨ Added
15
+
16
+ - **Speech-to-Speech Translation**: Now uses the correct `/api/v1/translation/translate/speech` endpoint
17
+ - Preserves original speaker voice characteristics during translation
18
+ - Supports both audio and video file translation
19
+ - Maintains speaker separation in multi-speaker content
20
+
21
+ - **URL-Based Translation**: Support for translating audio/video from URLs
22
+ - Direct media URL support (YouTube, audio links, etc.)
23
+ - No need to download files locally first
24
+
25
+ - **Enhanced Translation Job Management**:
26
+ - `list_translation_jobs()` - List translation history with pagination
27
+ - `retry_translation()` - Retry failed translation jobs
28
+ - `delete_translation_job()` - Delete translation jobs
29
+ - `translate_speech()` - Alias method for clearer API
30
+
31
+ ### 🔧 Fixed
32
+
33
+ - **Translation Endpoint**: Changed from generic `/translate` to speech-specific `/translate/speech`
34
+ - **API Schema Alignment**: Request and response formats now match the actual API
35
+ - **Response Model**: Updated `TranslationResult` to include all API response fields:
36
+ - `translated_audio_url` - Direct URL to translated audio
37
+ - `video_output_url` - Translated video output (when applicable)
38
+ - `transcript_urls` - Transcript files in multiple formats
39
+ - `display_name` - Original file display name
40
+ - `is_video` - Whether the input was a video file
41
+
42
+ ### 🏗️ Improved
43
+
44
+ - **Better Error Handling**: Enhanced validation for file vs URL inputs
45
+ - **Backward Compatibility**: Maintained `audio_output_url` property for existing code
46
+ - **Enhanced Examples**: Updated documentation and examples to show new features
47
+ - **Type Safety**: Improved type hints and validation
48
+
49
+ ### 📚 Documentation
50
+
51
+ - **Updated Examples**: `basic_usage.py` now demonstrates speech-to-speech translation
52
+ - **README Updates**: Corrected API usage examples with proper endpoint usage
53
+ - **Method Documentation**: Enhanced docstrings with accurate parameter descriptions
54
+
55
+ ### 🚀 Usage Examples
56
+
57
+ #### Fixed Speech Translation
58
+ ```python
59
+ # Speech-to-speech translation (preserves voice characteristics)
60
+ translation = client.translation.translate_speech(
61
+ audio_file="english_speech.wav",
62
+ target_language="es", # Spanish
63
+ source_language="en", # Optional - auto-detect
64
+ wait_for_completion=True
65
+ )
66
+
67
+ # URL-based translation
68
+ url_translation = client.translation.translate_speech(
69
+ url="https://example.com/audio.mp3",
70
+ target_language="fr", # French
71
+ wait_for_completion=True
72
+ )
73
+
74
+ # Job management
75
+ jobs = client.translation.list_translation_jobs(limit=10)
76
+ retry_job = client.translation.retry_translation(failed_job_id)
77
+ ```
78
+
79
+ ### 🔄 Migration Notes
80
+
81
+ - **No Breaking Changes**: Existing `translate_audio()` method continues to work
82
+ - **Enhanced Functionality**: Now uses proper speech-to-speech endpoint automatically
83
+ - **New Properties**: Additional response fields available in `TranslationResult`
84
+
85
+ ---
86
+
8
87
  ## [1.1.0] - 2024-01-15
9
88
 
10
89
  ### 🎉 Major API Compatibility Update
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: audiopod
3
- Version: 1.1.0
3
+ Version: 1.1.1
4
4
  Summary: Professional Audio Processing API Client for Python
5
5
  Home-page: https://github.com/audiopod-ai/audiopod-python
6
6
  Author: AudioPod AI
@@ -142,17 +142,25 @@ print(f"Transcript: {transcript.transcript}")
142
142
  print(f"Detected {len(transcript.segments)} speakers")
143
143
  ```
144
144
 
145
- #### Audio Translation
145
+ #### Speech-to-Speech Translation
146
146
 
147
147
  ```python
148
- # Translate audio to another language
149
- translation = client.translation.translate_audio(
148
+ # Translate speech while preserving voice characteristics
149
+ translation = client.translation.translate_speech(
150
150
  audio_file="path/to/english_audio.wav",
151
151
  target_language="es", # Spanish
152
+ source_language="en", # English (optional - auto-detect)
152
153
  wait_for_completion=True
153
154
  )
154
155
 
155
- print(f"Translated audio URL: {translation.audio_output_url}")
156
+ print(f"Translated audio URL: {translation.translated_audio_url}")
157
+
158
+ # Or translate from URL
159
+ url_translation = client.translation.translate_speech(
160
+ url="https://example.com/audio.mp3",
161
+ target_language="fr", # French
162
+ wait_for_completion=True
163
+ )
156
164
  ```
157
165
 
158
166
  ### Async Support
@@ -90,17 +90,25 @@ print(f"Transcript: {transcript.transcript}")
90
90
  print(f"Detected {len(transcript.segments)} speakers")
91
91
  ```
92
92
 
93
- #### Audio Translation
93
+ #### Speech-to-Speech Translation
94
94
 
95
95
  ```python
96
- # Translate audio to another language
97
- translation = client.translation.translate_audio(
96
+ # Translate speech while preserving voice characteristics
97
+ translation = client.translation.translate_speech(
98
98
  audio_file="path/to/english_audio.wav",
99
99
  target_language="es", # Spanish
100
+ source_language="en", # English (optional - auto-detect)
100
101
  wait_for_completion=True
101
102
  )
102
103
 
103
- print(f"Translated audio URL: {translation.audio_output_url}")
104
+ print(f"Translated audio URL: {translation.translated_audio_url}")
105
+
106
+ # Or translate from URL
107
+ url_translation = client.translation.translate_speech(
108
+ url="https://example.com/audio.mp3",
109
+ target_language="fr", # French
110
+ wait_for_completion=True
111
+ )
104
112
  ```
105
113
 
106
114
  ### Async Support
@@ -47,7 +47,7 @@ from .models import (
47
47
  TranslationResult
48
48
  )
49
49
 
50
- __version__ = "1.1.0"
50
+ __version__ = "1.1.1"
51
51
  __author__ = "AudioPod AI"
52
52
  __email__ = "support@audiopod.ai"
53
53
  __license__ = "MIT"
@@ -151,13 +151,18 @@ class MusicGenerationResult:
151
151
 
152
152
  @dataclass
153
153
  class TranslationResult:
154
- """Translation job result"""
154
+ """Speech translation job result"""
155
155
  job: Job
156
156
  source_language: Optional[str] = None
157
157
  target_language: Optional[str] = None
158
- audio_output_url: Optional[str] = None
159
- video_output_url: Optional[str] = None
158
+ display_name: Optional[str] = None
159
+ audio_output_path: Optional[str] = None
160
+ video_output_path: Optional[str] = None
160
161
  transcript_path: Optional[str] = None
162
+ translated_audio_url: Optional[str] = None
163
+ video_output_url: Optional[str] = None
164
+ transcript_urls: Optional[Dict[str, str]] = None
165
+ is_video: bool = False
161
166
 
162
167
  @classmethod
163
168
  def from_dict(cls, data: Dict[str, Any]) -> 'TranslationResult':
@@ -166,10 +171,20 @@ class TranslationResult:
166
171
  job=Job.from_dict(data),
167
172
  source_language=data.get('source_language'),
168
173
  target_language=data.get('target_language'),
169
- audio_output_url=data.get('audio_output_path'),
170
- video_output_url=data.get('video_output_path'),
171
- transcript_path=data.get('transcript_path')
174
+ display_name=data.get('display_name'),
175
+ audio_output_path=data.get('audio_output_path'),
176
+ video_output_path=data.get('video_output_path'),
177
+ transcript_path=data.get('transcript_path'),
178
+ translated_audio_url=data.get('translated_audio_url'),
179
+ video_output_url=data.get('video_output_url'),
180
+ transcript_urls=data.get('transcript_urls'),
181
+ is_video=data.get('is_video', False)
172
182
  )
183
+
184
+ @property
185
+ def audio_output_url(self) -> Optional[str]:
186
+ """Backward compatibility property - returns translated_audio_url"""
187
+ return self.translated_audio_url
173
188
 
174
189
 
175
190
  @dataclass
@@ -0,0 +1,196 @@
1
+ """
2
+ Translation Service - Speech-to-speech translation operations
3
+ """
4
+
5
+ from typing import Optional, Union
6
+ from .base import BaseService
7
+ from ..models import Job, TranslationResult
8
+ from ..exceptions import ValidationError
9
+
10
+
11
+ class TranslationService(BaseService):
12
+ """Service for speech-to-speech translation operations"""
13
+
14
+ def translate_audio(
15
+ self,
16
+ audio_file: Optional[str] = None,
17
+ url: Optional[str] = None,
18
+ target_language: str = "en",
19
+ source_language: Optional[str] = None,
20
+ wait_for_completion: bool = False,
21
+ timeout: int = 900
22
+ ) -> Union[Job, TranslationResult]:
23
+ """
24
+ Translate speech from audio/video file to another language while preserving voice characteristics
25
+
26
+ Args:
27
+ audio_file: Path to audio/video file (required if no URL)
28
+ url: Direct media URL (required if no file)
29
+ target_language: Target language code (ISO 639-1, e.g., 'es' for Spanish)
30
+ source_language: Source language code (auto-detect if None)
31
+ wait_for_completion: Whether to wait for completion
32
+ timeout: Maximum time to wait
33
+
34
+ Returns:
35
+ Job object or translation result
36
+ """
37
+ if not audio_file and not url:
38
+ raise ValidationError("Either audio_file or url must be provided")
39
+
40
+ if audio_file and url:
41
+ raise ValidationError("Provide either audio_file or url, not both")
42
+
43
+ target_language = self._validate_language_code(target_language)
44
+ if source_language:
45
+ source_language = self._validate_language_code(source_language)
46
+
47
+ # Prepare request data
48
+ files = {}
49
+ data = {"target_language": target_language}
50
+
51
+ if audio_file:
52
+ files = self._prepare_file_upload(audio_file, "file")
53
+
54
+ if url:
55
+ data["url"] = url
56
+
57
+ if source_language:
58
+ data["source_language"] = source_language
59
+
60
+ if self.async_mode:
61
+ return self._async_translate_audio(files, data, wait_for_completion, timeout)
62
+ else:
63
+ response = self.client.request(
64
+ "POST",
65
+ "/api/v1/translation/translate/speech", # FIXED: Use correct speech-to-speech endpoint
66
+ data=data,
67
+ files=files if files else None
68
+ )
69
+ job = Job.from_dict(response)
70
+
71
+ if wait_for_completion:
72
+ completed_job = self._wait_for_completion(job.id, timeout)
73
+ return TranslationResult.from_dict(completed_job.result or completed_job.__dict__)
74
+
75
+ return job
76
+
77
+ def translate_speech(
78
+ self,
79
+ audio_file: Optional[str] = None,
80
+ url: Optional[str] = None,
81
+ target_language: str = "en",
82
+ source_language: Optional[str] = None,
83
+ wait_for_completion: bool = False,
84
+ timeout: int = 900
85
+ ) -> Union[Job, TranslationResult]:
86
+ """
87
+ Alias for translate_audio - more descriptive method name for speech translation
88
+ """
89
+ return self.translate_audio(
90
+ audio_file=audio_file,
91
+ url=url,
92
+ target_language=target_language,
93
+ source_language=source_language,
94
+ wait_for_completion=wait_for_completion,
95
+ timeout=timeout
96
+ )
97
+
98
+ async def _async_translate_audio(self, files, data, wait_for_completion, timeout):
99
+ """Async version of translate_audio"""
100
+ response = await self.client.request(
101
+ "POST",
102
+ "/api/v1/translation/translate/speech", # FIXED: Use correct speech-to-speech endpoint
103
+ data=data,
104
+ files=files if files else None
105
+ )
106
+ job = Job.from_dict(response)
107
+
108
+ if wait_for_completion:
109
+ completed_job = await self._async_wait_for_completion(job.id, timeout)
110
+ return TranslationResult.from_dict(completed_job.result or completed_job.__dict__)
111
+
112
+ return job
113
+
114
+ def get_translation_job(self, job_id: int) -> TranslationResult:
115
+ """Get translation job details"""
116
+ if self.async_mode:
117
+ return self._async_get_translation_job(job_id)
118
+ else:
119
+ response = self.client.request("GET", f"/api/v1/translation/translations/{job_id}")
120
+ return TranslationResult.from_dict(response)
121
+
122
+ async def _async_get_translation_job(self, job_id: int) -> TranslationResult:
123
+ """Async version of get_translation_job"""
124
+ response = await self.client.request("GET", f"/api/v1/translation/translations/{job_id}")
125
+ return TranslationResult.from_dict(response)
126
+
127
+ def list_translation_jobs(
128
+ self,
129
+ skip: int = 0,
130
+ limit: int = 50
131
+ ) -> list:
132
+ """
133
+ List translation jobs
134
+
135
+ Args:
136
+ skip: Number of jobs to skip (pagination offset)
137
+ limit: Maximum number of jobs to return (max 100)
138
+
139
+ Returns:
140
+ List of translation jobs
141
+ """
142
+ params = {
143
+ "skip": skip,
144
+ "limit": min(limit, 100) # API max is 100
145
+ }
146
+
147
+ if self.async_mode:
148
+ return self._async_list_translation_jobs(params)
149
+ else:
150
+ response = self.client.request("GET", "/api/v1/translation/translations", params=params)
151
+ return [TranslationResult.from_dict(job_data) for job_data in response]
152
+
153
+ async def _async_list_translation_jobs(self, params: dict) -> list:
154
+ """Async version of list_translation_jobs"""
155
+ response = await self.client.request("GET", "/api/v1/translation/translations", params=params)
156
+ return [TranslationResult.from_dict(job_data) for job_data in response]
157
+
158
+ def retry_translation(self, job_id: int) -> Job:
159
+ """
160
+ Retry a failed translation job
161
+
162
+ Args:
163
+ job_id: ID of the failed translation job to retry
164
+
165
+ Returns:
166
+ New job object for the retry attempt
167
+ """
168
+ if self.async_mode:
169
+ return self._async_retry_translation(job_id)
170
+ else:
171
+ response = self.client.request("POST", f"/api/v1/translation/translations/{job_id}/retry")
172
+ return Job.from_dict(response)
173
+
174
+ async def _async_retry_translation(self, job_id: int) -> Job:
175
+ """Async version of retry_translation"""
176
+ response = await self.client.request("POST", f"/api/v1/translation/translations/{job_id}/retry")
177
+ return Job.from_dict(response)
178
+
179
+ def delete_translation_job(self, job_id: int) -> dict:
180
+ """
181
+ Delete a translation job
182
+
183
+ Args:
184
+ job_id: ID of the translation job to delete
185
+
186
+ Returns:
187
+ Deletion confirmation
188
+ """
189
+ if self.async_mode:
190
+ return self._async_delete_translation_job(job_id)
191
+ else:
192
+ return self.client.request("DELETE", f"/api/v1/translation/translations/{job_id}")
193
+
194
+ async def _async_delete_translation_job(self, job_id: int) -> dict:
195
+ """Async version of delete_translation_job"""
196
+ return await self.client.request("DELETE", f"/api/v1/translation/translations/{job_id}")
@@ -227,8 +227,8 @@ def transcription_example(client):
227
227
 
228
228
 
229
229
  def translation_example(client):
230
- """Demonstrate audio translation"""
231
- print("\n🌍 Translation Example")
230
+ """Demonstrate speech-to-speech translation"""
231
+ print("\n🌍 Speech Translation Example")
232
232
  print("=" * 50)
233
233
 
234
234
  audio_file = "examples/english_speech.wav"
@@ -236,23 +236,59 @@ def translation_example(client):
236
236
  if not Path(audio_file).exists():
237
237
  print(f"⚠️ Audio file not found: {audio_file}")
238
238
  print(" Please provide an English audio file to test translation")
239
+ print(" Alternatively, you can use a URL - see example below")
240
+
241
+ # Show URL-based translation example
242
+ try:
243
+ print("\n🔄 Trying URL-based translation example...")
244
+
245
+ translation_job = client.translation.translate_speech(
246
+ url="https://example.com/sample_english.wav", # Example URL
247
+ target_language="es", # Spanish
248
+ source_language="en", # English
249
+ wait_for_completion=False # Don't wait for this example
250
+ )
251
+
252
+ print(f"📋 URL translation job started: {translation_job.id}")
253
+ print(" Note: This is just an example - replace with a real audio URL")
254
+
255
+ except AudioPodError as e:
256
+ print(f" Expected error (example URL): {e.message}")
257
+
239
258
  return
240
259
 
241
260
  try:
242
- print(f"🔄 Translating audio to Spanish...")
261
+ print(f"🔄 Translating speech to Spanish (preserving voice characteristics)...")
243
262
 
244
263
  translation_job = client.translation.translate_audio(
245
264
  audio_file=audio_file,
246
265
  target_language="es", # Spanish
247
- source_language="en", # English
266
+ source_language="en", # English (optional - auto-detect if not specified)
248
267
  wait_for_completion=True,
249
268
  timeout=900 # 15 minutes for translation
250
269
  )
251
270
 
252
- print("✅ Translation completed!")
253
- print(f"🎵 Translated audio: {translation_job.audio_output_url}")
271
+ print("✅ Speech translation completed!")
272
+ print(f"🎵 Translated audio: {translation_job.translated_audio_url}")
273
+ print(f"🎬 Video output: {translation_job.video_output_url}")
254
274
  print(f"📝 Source language: {translation_job.source_language}")
255
275
  print(f"🎯 Target language: {translation_job.target_language}")
276
+ print(f"📄 Display name: {translation_job.display_name}")
277
+
278
+ if translation_job.transcript_urls:
279
+ print("📋 Transcript URLs:")
280
+ for format_type, url in translation_job.transcript_urls.items():
281
+ print(f" {format_type}: {url}")
282
+
283
+ # Demonstrate additional translation methods
284
+ print("\n🔄 Demonstrating job management...")
285
+
286
+ # List recent translation jobs
287
+ jobs = client.translation.list_translation_jobs(limit=5)
288
+ print(f"📋 Found {len(jobs)} recent translation jobs")
289
+
290
+ # Show job retry capability (don't actually retry)
291
+ print(f"🔄 Job retry available for failed jobs: translation.retry_translation({translation_job.job.id})")
256
292
 
257
293
  except AudioPodError as e:
258
294
  print(f"❌ Translation error: {e.message}")
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "audiopod"
7
- version = "1.1.0"
7
+ version = "1.1.1"
8
8
  authors = [
9
9
  {name = "AudioPod AI", email = "support@audiopod.ai"},
10
10
  ]
@@ -1,81 +0,0 @@
1
- """
2
- Translation Service - Audio/video translation operations
3
- """
4
-
5
- from typing import Optional, Union
6
- from .base import BaseService
7
- from ..models import Job, TranslationResult
8
-
9
-
10
- class TranslationService(BaseService):
11
- """Service for audio and video translation operations"""
12
-
13
- def translate_audio(
14
- self,
15
- audio_file: str,
16
- target_language: str,
17
- source_language: Optional[str] = None,
18
- wait_for_completion: bool = False,
19
- timeout: int = 900
20
- ) -> Union[Job, TranslationResult]:
21
- """
22
- Translate audio to another language
23
-
24
- Args:
25
- audio_file: Path to audio file
26
- target_language: Target language code
27
- source_language: Source language (auto-detect if None)
28
- wait_for_completion: Whether to wait for completion
29
- timeout: Maximum time to wait
30
-
31
- Returns:
32
- Job object or translation result
33
- """
34
- target_language = self._validate_language_code(target_language)
35
- if source_language:
36
- source_language = self._validate_language_code(source_language)
37
-
38
- files = self._prepare_file_upload(audio_file, "file")
39
- data = {"target_language": target_language}
40
- if source_language:
41
- data["source_language"] = source_language
42
-
43
- if self.async_mode:
44
- return self._async_translate_audio(files, data, wait_for_completion, timeout)
45
- else:
46
- response = self.client.request(
47
- "POST", "/api/v1/translation/translate", data=data, files=files
48
- )
49
- job = Job.from_dict(response)
50
-
51
- if wait_for_completion:
52
- completed_job = self._wait_for_completion(job.id, timeout)
53
- return TranslationResult.from_dict(completed_job.result or completed_job.__dict__)
54
-
55
- return job
56
-
57
- async def _async_translate_audio(self, files, data, wait_for_completion, timeout):
58
- """Async version of translate_audio"""
59
- response = await self.client.request(
60
- "POST", "/api/v1/translation/translate", data=data, files=files
61
- )
62
- job = Job.from_dict(response)
63
-
64
- if wait_for_completion:
65
- completed_job = await self._async_wait_for_completion(job.id, timeout)
66
- return TranslationResult.from_dict(completed_job.result or completed_job.__dict__)
67
-
68
- return job
69
-
70
- def get_translation_job(self, job_id: int) -> TranslationResult:
71
- """Get translation job details"""
72
- if self.async_mode:
73
- return self._async_get_translation_job(job_id)
74
- else:
75
- response = self.client.request("GET", f"/api/v1/translation/translations/{job_id}")
76
- return TranslationResult.from_dict(response)
77
-
78
- async def _async_get_translation_job(self, job_id: int) -> TranslationResult:
79
- """Async version of get_translation_job"""
80
- response = await self.client.request("GET", f"/api/v1/translation/translations/{job_id}")
81
- return TranslationResult.from_dict(response)
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