audiopod 1.0.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.
@@ -0,0 +1,51 @@
1
+ """
2
+ Denoiser Service - Audio denoising operations
3
+ """
4
+
5
+ from typing import Optional, Union
6
+ from .base import BaseService
7
+ from ..models import Job, DenoiseResult
8
+
9
+
10
+ class DenoiserService(BaseService):
11
+ """Service for audio denoising operations"""
12
+
13
+ def denoise_audio(
14
+ self,
15
+ audio_file: str,
16
+ quality_mode: str = "balanced",
17
+ wait_for_completion: bool = False,
18
+ timeout: int = 600
19
+ ) -> Union[Job, DenoiseResult]:
20
+ """Remove noise from audio"""
21
+ files = self._prepare_file_upload(audio_file, "file")
22
+ data = {"quality_mode": quality_mode}
23
+
24
+ if self.async_mode:
25
+ return self._async_denoise(files, data, wait_for_completion, timeout)
26
+ else:
27
+ response = self.client.request(
28
+ "POST", "/api/v1/denoiser/denoise",
29
+ data=data, files=files
30
+ )
31
+ job = Job.from_dict(response)
32
+
33
+ if wait_for_completion:
34
+ completed_job = self._wait_for_completion(job.id, timeout)
35
+ return DenoiseResult.from_dict(completed_job.result or completed_job.__dict__)
36
+
37
+ return job
38
+
39
+ async def _async_denoise(self, files, data, wait_for_completion, timeout):
40
+ """Async version of denoise_audio"""
41
+ response = await self.client.request(
42
+ "POST", "/api/v1/denoiser/denoise",
43
+ data=data, files=files
44
+ )
45
+ job = Job.from_dict(response)
46
+
47
+ if wait_for_completion:
48
+ completed_job = await self._async_wait_for_completion(job.id, timeout)
49
+ return DenoiseResult.from_dict(completed_job.result or completed_job.__dict__)
50
+
51
+ return job
@@ -0,0 +1,61 @@
1
+ """
2
+ Karaoke Service - Karaoke video generation
3
+ """
4
+
5
+ from typing import Optional, Union
6
+ from .base import BaseService
7
+ from ..models import Job
8
+
9
+
10
+ class KaraokeService(BaseService):
11
+ """Service for karaoke video generation"""
12
+
13
+ def generate_karaoke(
14
+ self,
15
+ audio_file: Optional[str] = None,
16
+ youtube_url: Optional[str] = None,
17
+ custom_lyrics: Optional[str] = None,
18
+ video_style: str = "modern",
19
+ wait_for_completion: bool = False,
20
+ timeout: int = 1200
21
+ ) -> Job:
22
+ """Generate karaoke video"""
23
+ if not audio_file and not youtube_url:
24
+ raise ValueError("Either audio_file or youtube_url must be provided")
25
+
26
+ data = {"video_style": video_style}
27
+ files = {}
28
+
29
+ if audio_file:
30
+ files = self._prepare_file_upload(audio_file, "file")
31
+ if youtube_url:
32
+ data["youtube_url"] = youtube_url
33
+ if custom_lyrics:
34
+ data["custom_lyrics"] = custom_lyrics
35
+
36
+ if self.async_mode:
37
+ return self._async_generate_karaoke(files, data, wait_for_completion, timeout)
38
+ else:
39
+ response = self.client.request(
40
+ "POST", "/api/v1/karaoke/generate",
41
+ data=data, files=files if files else None
42
+ )
43
+ job = Job.from_dict(response)
44
+
45
+ if wait_for_completion:
46
+ return self._wait_for_completion(job.id, timeout)
47
+
48
+ return job
49
+
50
+ async def _async_generate_karaoke(self, files, data, wait_for_completion, timeout):
51
+ """Async version of generate_karaoke"""
52
+ response = await self.client.request(
53
+ "POST", "/api/v1/karaoke/generate",
54
+ data=data, files=files if files else None
55
+ )
56
+ job = Job.from_dict(response)
57
+
58
+ if wait_for_completion:
59
+ return await self._async_wait_for_completion(job.id, timeout)
60
+
61
+ return job
@@ -0,0 +1,434 @@
1
+ """
2
+ Music Service - Music generation operations
3
+ """
4
+
5
+ from typing import List, Optional, Dict, Any, Union
6
+ from pathlib import Path
7
+
8
+ from .base import BaseService
9
+ from ..models import Job, MusicGenerationResult
10
+ from ..exceptions import ValidationError
11
+
12
+
13
+ class MusicService(BaseService):
14
+ """Service for music generation operations"""
15
+
16
+ def generate_music(
17
+ self,
18
+ prompt: str,
19
+ duration: float = 120.0,
20
+ guidance_scale: float = 7.5,
21
+ num_inference_steps: int = 50,
22
+ seed: Optional[int] = None,
23
+ display_name: Optional[str] = None,
24
+ wait_for_completion: bool = False,
25
+ timeout: int = 600
26
+ ) -> Union[Job, MusicGenerationResult]:
27
+ """
28
+ Generate music from text prompt
29
+
30
+ Args:
31
+ prompt: Text description of the music to generate
32
+ duration: Duration in seconds (10-600)
33
+ guidance_scale: How closely to follow the prompt (1.0-20.0)
34
+ num_inference_steps: Number of denoising steps (20-100)
35
+ seed: Random seed for reproducible results
36
+ display_name: Custom name for the generated track
37
+ wait_for_completion: Whether to wait for generation completion
38
+ timeout: Maximum time to wait if wait_for_completion=True
39
+
40
+ Returns:
41
+ Job object if wait_for_completion=False, otherwise MusicGenerationResult
42
+ """
43
+ # Validate inputs
44
+ prompt = self._validate_text_input(prompt, max_length=1000)
45
+ if not 10.0 <= duration <= 600.0:
46
+ raise ValidationError("Duration must be between 10 and 600 seconds")
47
+ if not 1.0 <= guidance_scale <= 20.0:
48
+ raise ValidationError("Guidance scale must be between 1.0 and 20.0")
49
+ if not 20 <= num_inference_steps <= 100:
50
+ raise ValidationError("Inference steps must be between 20 and 100")
51
+ if seed is not None and (seed < 0 or seed > 2**32 - 1):
52
+ raise ValidationError("Seed must be between 0 and 2^32 - 1")
53
+
54
+ # Prepare request data
55
+ data = {
56
+ "prompt": prompt,
57
+ "duration": duration,
58
+ "guidance_scale": guidance_scale,
59
+ "num_inference_steps": num_inference_steps
60
+ }
61
+ if seed is not None:
62
+ data["seed"] = seed
63
+ if display_name:
64
+ data["display_name"] = display_name.strip()
65
+
66
+ # Make request
67
+ if self.async_mode:
68
+ return self._async_generate_music(data, wait_for_completion, timeout)
69
+ else:
70
+ response = self.client.request("POST", "/api/v1/music/text2music", data=data)
71
+ job = Job.from_dict(response)
72
+
73
+ if wait_for_completion:
74
+ completed_job = self._wait_for_completion(job.id, timeout)
75
+ return MusicGenerationResult.from_dict(completed_job.result or completed_job.__dict__)
76
+
77
+ return job
78
+
79
+ async def _async_generate_music(
80
+ self,
81
+ data: Dict[str, Any],
82
+ wait_for_completion: bool,
83
+ timeout: int
84
+ ) -> Union[Job, MusicGenerationResult]:
85
+ """Async version of generate_music"""
86
+ response = await self.client.request("POST", "/api/v1/music/text2music", data=data)
87
+ job = Job.from_dict(response)
88
+
89
+ if wait_for_completion:
90
+ completed_job = await self._async_wait_for_completion(job.id, timeout)
91
+ return MusicGenerationResult.from_dict(completed_job.result or completed_job.__dict__)
92
+
93
+ return job
94
+
95
+ def generate_rap(
96
+ self,
97
+ lyrics: str,
98
+ style: str = "modern",
99
+ tempo: int = 120,
100
+ display_name: Optional[str] = None,
101
+ wait_for_completion: bool = False,
102
+ timeout: int = 600
103
+ ) -> Union[Job, MusicGenerationResult]:
104
+ """
105
+ Generate rap music with lyrics
106
+
107
+ Args:
108
+ lyrics: Rap lyrics
109
+ style: Style of rap ('modern', 'classic', 'trap')
110
+ tempo: Beats per minute (80-200)
111
+ display_name: Custom name for the track
112
+ wait_for_completion: Whether to wait for completion
113
+ timeout: Maximum time to wait
114
+
115
+ Returns:
116
+ Job object or generation result
117
+ """
118
+ # Validate inputs
119
+ lyrics = self._validate_text_input(lyrics, max_length=2000)
120
+ if not 80 <= tempo <= 200:
121
+ raise ValidationError("Tempo must be between 80 and 200 BPM")
122
+ if style not in ["modern", "classic", "trap"]:
123
+ raise ValidationError("Style must be 'modern', 'classic', or 'trap'")
124
+
125
+ # Prepare request data
126
+ data = {
127
+ "lyrics": lyrics,
128
+ "style": style,
129
+ "tempo": tempo
130
+ }
131
+ if display_name:
132
+ data["display_name"] = display_name.strip()
133
+
134
+ # Make request
135
+ if self.async_mode:
136
+ return self._async_generate_rap(data, wait_for_completion, timeout)
137
+ else:
138
+ response = self.client.request("POST", "/api/v1/music/text2rap", data=data)
139
+ job = Job.from_dict(response)
140
+
141
+ if wait_for_completion:
142
+ completed_job = self._wait_for_completion(job.id, timeout)
143
+ return MusicGenerationResult.from_dict(completed_job.result or completed_job.__dict__)
144
+
145
+ return job
146
+
147
+ async def _async_generate_rap(
148
+ self,
149
+ data: Dict[str, Any],
150
+ wait_for_completion: bool,
151
+ timeout: int
152
+ ) -> Union[Job, MusicGenerationResult]:
153
+ """Async version of generate_rap"""
154
+ response = await self.client.request("POST", "/api/v1/music/text2rap", data=data)
155
+ job = Job.from_dict(response)
156
+
157
+ if wait_for_completion:
158
+ completed_job = await self._async_wait_for_completion(job.id, timeout)
159
+ return MusicGenerationResult.from_dict(completed_job.result or completed_job.__dict__)
160
+
161
+ return job
162
+
163
+ def generate_instrumental(
164
+ self,
165
+ prompt: str,
166
+ duration: float = 120.0,
167
+ instruments: Optional[List[str]] = None,
168
+ key: Optional[str] = None,
169
+ tempo: Optional[int] = None,
170
+ display_name: Optional[str] = None,
171
+ wait_for_completion: bool = False,
172
+ timeout: int = 600
173
+ ) -> Union[Job, MusicGenerationResult]:
174
+ """
175
+ Generate instrumental music
176
+
177
+ Args:
178
+ prompt: Description of the instrumental
179
+ duration: Duration in seconds
180
+ instruments: List of instruments to include
181
+ key: Musical key (e.g., 'C', 'Am', 'F#')
182
+ tempo: Beats per minute
183
+ display_name: Custom name for the track
184
+ wait_for_completion: Whether to wait for completion
185
+ timeout: Maximum time to wait
186
+
187
+ Returns:
188
+ Job object or generation result
189
+ """
190
+ # Validate inputs
191
+ prompt = self._validate_text_input(prompt, max_length=1000)
192
+ if not 10.0 <= duration <= 600.0:
193
+ raise ValidationError("Duration must be between 10 and 600 seconds")
194
+ if tempo is not None and not 60 <= tempo <= 200:
195
+ raise ValidationError("Tempo must be between 60 and 200 BPM")
196
+
197
+ # Prepare request data
198
+ data = {
199
+ "prompt": prompt,
200
+ "duration": duration
201
+ }
202
+ if instruments:
203
+ data["instruments"] = instruments
204
+ if key:
205
+ data["key"] = key
206
+ if tempo:
207
+ data["tempo"] = tempo
208
+ if display_name:
209
+ data["display_name"] = display_name.strip()
210
+
211
+ # Make request
212
+ if self.async_mode:
213
+ return self._async_generate_instrumental(data, wait_for_completion, timeout)
214
+ else:
215
+ response = self.client.request("POST", "/api/v1/music/prompt2instrumental", data=data)
216
+ job = Job.from_dict(response)
217
+
218
+ if wait_for_completion:
219
+ completed_job = self._wait_for_completion(job.id, timeout)
220
+ return MusicGenerationResult.from_dict(completed_job.result or completed_job.__dict__)
221
+
222
+ return job
223
+
224
+ async def _async_generate_instrumental(
225
+ self,
226
+ data: Dict[str, Any],
227
+ wait_for_completion: bool,
228
+ timeout: int
229
+ ) -> Union[Job, MusicGenerationResult]:
230
+ """Async version of generate_instrumental"""
231
+ response = await self.client.request("POST", "/api/v1/music/prompt2instrumental", data=data)
232
+ job = Job.from_dict(response)
233
+
234
+ if wait_for_completion:
235
+ completed_job = await self._async_wait_for_completion(job.id, timeout)
236
+ return MusicGenerationResult.from_dict(completed_job.result or completed_job.__dict__)
237
+
238
+ return job
239
+
240
+ def extend_music(
241
+ self,
242
+ source_job_id: int,
243
+ extend_duration: float = 30.0,
244
+ display_name: Optional[str] = None,
245
+ wait_for_completion: bool = False,
246
+ timeout: int = 600
247
+ ) -> Union[Job, MusicGenerationResult]:
248
+ """
249
+ Extend an existing music track
250
+
251
+ Args:
252
+ source_job_id: ID of the original music generation job
253
+ extend_duration: How many seconds to extend
254
+ display_name: Custom name for the extended track
255
+ wait_for_completion: Whether to wait for completion
256
+ timeout: Maximum time to wait
257
+
258
+ Returns:
259
+ Job object or generation result
260
+ """
261
+ # Validate inputs
262
+ if not 5.0 <= extend_duration <= 120.0:
263
+ raise ValidationError("Extend duration must be between 5 and 120 seconds")
264
+
265
+ # Prepare request data
266
+ data = {
267
+ "source_job_id": source_job_id,
268
+ "extend_duration": extend_duration
269
+ }
270
+ if display_name:
271
+ data["display_name"] = display_name.strip()
272
+
273
+ # Make request
274
+ if self.async_mode:
275
+ return self._async_extend_music(data, wait_for_completion, timeout)
276
+ else:
277
+ response = self.client.request("POST", "/api/v1/music/extend", data=data)
278
+ job = Job.from_dict(response)
279
+
280
+ if wait_for_completion:
281
+ completed_job = self._wait_for_completion(job.id, timeout)
282
+ return MusicGenerationResult.from_dict(completed_job.result or completed_job.__dict__)
283
+
284
+ return job
285
+
286
+ async def _async_extend_music(
287
+ self,
288
+ data: Dict[str, Any],
289
+ wait_for_completion: bool,
290
+ timeout: int
291
+ ) -> Union[Job, MusicGenerationResult]:
292
+ """Async version of extend_music"""
293
+ response = await self.client.request("POST", "/api/v1/music/extend", data=data)
294
+ job = Job.from_dict(response)
295
+
296
+ if wait_for_completion:
297
+ completed_job = await self._async_wait_for_completion(job.id, timeout)
298
+ return MusicGenerationResult.from_dict(completed_job.result or completed_job.__dict__)
299
+
300
+ return job
301
+
302
+ def list_music_jobs(
303
+ self,
304
+ limit: int = 50,
305
+ offset: int = 0,
306
+ status: Optional[str] = None,
307
+ task: Optional[str] = None,
308
+ liked: Optional[bool] = None
309
+ ) -> List[MusicGenerationResult]:
310
+ """
311
+ List music generation jobs
312
+
313
+ Args:
314
+ limit: Maximum number of results
315
+ offset: Number of results to skip
316
+ status: Filter by job status
317
+ task: Filter by task type
318
+ liked: Filter by liked status
319
+
320
+ Returns:
321
+ List of music generation results
322
+ """
323
+ params = {
324
+ "limit": limit,
325
+ "skip": offset
326
+ }
327
+ if status:
328
+ params["status"] = status
329
+ if task:
330
+ params["task"] = task
331
+ if liked is not None:
332
+ params["liked"] = liked
333
+
334
+ if self.async_mode:
335
+ return self._async_list_music_jobs(params)
336
+ else:
337
+ response = self.client.request("GET", "/api/v1/music/jobs", params=params)
338
+ return [MusicGenerationResult.from_dict(job_data) for job_data in response]
339
+
340
+ async def _async_list_music_jobs(self, params: Dict[str, Any]) -> List[MusicGenerationResult]:
341
+ """Async version of list_music_jobs"""
342
+ response = await self.client.request("GET", "/api/v1/music/jobs", params=params)
343
+ return [MusicGenerationResult.from_dict(job_data) for job_data in response]
344
+
345
+ def get_music_job(self, job_id: int) -> MusicGenerationResult:
346
+ """
347
+ Get details of a specific music generation job
348
+
349
+ Args:
350
+ job_id: ID of the music job
351
+
352
+ Returns:
353
+ Music generation result
354
+ """
355
+ if self.async_mode:
356
+ return self._async_get_music_job(job_id)
357
+ else:
358
+ response = self.client.request("GET", f"/api/v1/music/jobs/{job_id}/status")
359
+ return MusicGenerationResult.from_dict(response)
360
+
361
+ async def _async_get_music_job(self, job_id: int) -> MusicGenerationResult:
362
+ """Async version of get_music_job"""
363
+ response = await self.client.request("GET", f"/api/v1/music/jobs/{job_id}/status")
364
+ return MusicGenerationResult.from_dict(response)
365
+
366
+ def like_music_track(self, job_id: int) -> Dict[str, Any]:
367
+ """
368
+ Like a music track
369
+
370
+ Args:
371
+ job_id: ID of the music job
372
+
373
+ Returns:
374
+ Like response
375
+ """
376
+ if self.async_mode:
377
+ return self._async_like_music_track(job_id)
378
+ else:
379
+ return self.client.request("POST", f"/api/v1/music/jobs/{job_id}/like")
380
+
381
+ async def _async_like_music_track(self, job_id: int) -> Dict[str, Any]:
382
+ """Async version of like_music_track"""
383
+ return await self.client.request("POST", f"/api/v1/music/jobs/{job_id}/like")
384
+
385
+ def share_music_track(
386
+ self,
387
+ job_id: int,
388
+ platform: Optional[str] = None,
389
+ message: Optional[str] = None
390
+ ) -> Dict[str, Any]:
391
+ """
392
+ Share a music track
393
+
394
+ Args:
395
+ job_id: ID of the music job
396
+ platform: Platform to share on
397
+ message: Optional message to include
398
+
399
+ Returns:
400
+ Share response with shareable URL
401
+ """
402
+ data = {}
403
+ if platform:
404
+ data["platform"] = platform
405
+ if message:
406
+ data["message"] = message
407
+
408
+ if self.async_mode:
409
+ return self._async_share_music_track(job_id, data)
410
+ else:
411
+ return self.client.request("POST", f"/api/v1/music/jobs/{job_id}/share", data=data)
412
+
413
+ async def _async_share_music_track(self, job_id: int, data: Dict[str, Any]) -> Dict[str, Any]:
414
+ """Async version of share_music_track"""
415
+ return await self.client.request("POST", f"/api/v1/music/jobs/{job_id}/share", data=data)
416
+
417
+ def delete_music_job(self, job_id: int) -> Dict[str, str]:
418
+ """
419
+ Delete a music generation job
420
+
421
+ Args:
422
+ job_id: ID of the music job
423
+
424
+ Returns:
425
+ Deletion confirmation
426
+ """
427
+ if self.async_mode:
428
+ return self._async_delete_music_job(job_id)
429
+ else:
430
+ return self.client.request("DELETE", f"/api/v1/music/jobs/{job_id}")
431
+
432
+ async def _async_delete_music_job(self, job_id: int) -> Dict[str, str]:
433
+ """Async version of delete_music_job"""
434
+ return await self.client.request("DELETE", f"/api/v1/music/jobs/{job_id}")
@@ -0,0 +1,53 @@
1
+ """
2
+ Speaker Service - Speaker analysis and diarization
3
+ """
4
+
5
+ from typing import Optional, Union
6
+ from .base import BaseService
7
+ from ..models import Job, SpeakerAnalysisResult
8
+
9
+
10
+ class SpeakerService(BaseService):
11
+ """Service for speaker diarization and analysis"""
12
+
13
+ def diarize_speakers(
14
+ self,
15
+ audio_file: str,
16
+ num_speakers: Optional[int] = None,
17
+ wait_for_completion: bool = False,
18
+ timeout: int = 600
19
+ ) -> Union[Job, SpeakerAnalysisResult]:
20
+ """Identify and separate speakers in audio"""
21
+ files = self._prepare_file_upload(audio_file, "file")
22
+ data = {}
23
+ if num_speakers:
24
+ data["num_speakers"] = num_speakers
25
+
26
+ if self.async_mode:
27
+ return self._async_diarize(files, data, wait_for_completion, timeout)
28
+ else:
29
+ response = self.client.request(
30
+ "POST", "/api/v1/speaker/diarize",
31
+ data=data, files=files
32
+ )
33
+ job = Job.from_dict(response)
34
+
35
+ if wait_for_completion:
36
+ completed_job = self._wait_for_completion(job.id, timeout)
37
+ return SpeakerAnalysisResult.from_dict(completed_job.result or completed_job.__dict__)
38
+
39
+ return job
40
+
41
+ async def _async_diarize(self, files, data, wait_for_completion, timeout):
42
+ """Async version of diarize_speakers"""
43
+ response = await self.client.request(
44
+ "POST", "/api/v1/speaker/diarize",
45
+ data=data, files=files
46
+ )
47
+ job = Job.from_dict(response)
48
+
49
+ if wait_for_completion:
50
+ completed_job = await self._async_wait_for_completion(job.id, timeout)
51
+ return SpeakerAnalysisResult.from_dict(completed_job.result or completed_job.__dict__)
52
+
53
+ return job