Files

239 lines
10 KiB
Python

"""
Pydantic models for API requests and responses.
Inspired by OpenAI's API but tailored for Qwen3-TTS.
"""
from typing import List, Optional, Dict, Any
from enum import Enum
from pydantic import BaseModel, Field
class TTSModel(str, Enum):
"""Available TTS models."""
BASE = "Qwen/Qwen3-TTS-12Hz-1.7B-Base"
# Add more model variants as needed
class VoiceCloneMode(str, Enum):
"""Voice cloning modes."""
DISABLED = "disabled"
REFERENCE_AUDIO = "reference_audio"
CUSTOM = "custom"
class StreamOptions(BaseModel):
"""Streaming configuration options."""
emit_every_frames: int = Field(default=8, ge=1, le=100, description="Emit chunks every N frames")
decode_window_frames: int = Field(default=80, ge=1, le=256, description="Decode window size in frames")
overlap_samples: int = Field(default=512, ge=0, le=2048, description="Overlap samples for smooth transitions")
class TTSRequest(BaseModel):
"""Base TTS request model."""
text: str = Field(..., min_length=1, max_length=10000, description="Text to synthesize")
model: TTSModel = Field(default=TTSModel.BASE, description="Model to use")
language: str = Field(default="English", description="Language for TTS")
voice_clone_mode: VoiceCloneMode = Field(default=VoiceCloneMode.DISABLED, description="Voice cloning mode")
speed: float = Field(default=1.0, ge=0.5, le=2.0, description="Speech speed multiplier")
pitch: float = Field(default=1.0, ge=0.5, le=2.0, description="Pitch adjustment")
class StreamingTTSRequest(TTSRequest):
"""Request model for streaming TTS."""
stream_options: StreamOptions = Field(default_factory=StreamOptions, description="Streaming configuration")
class TTSResponse(BaseModel):
"""Response model for TTS requests."""
id: str = Field(..., description="Request ID")
object: str = Field(default="audio", description="Object type")
created: int = Field(..., description="Unix timestamp of creation")
model: str = Field(..., description="Model used")
audio_base64: str = Field(..., description="Audio data in base64 format")
duration: float = Field(..., description="Duration in seconds")
sample_rate: int = Field(default=24000, description="Sample rate in Hz")
language: str = Field(..., description="Language used")
class ErrorResponse(BaseModel):
"""Error response model."""
error: str = Field(..., description="Error message")
code: str = Field(..., description="Error code")
details: Optional[Dict[str, Any]] = Field(default=None, description="Additional error details")
class HealthResponse(BaseModel):
"""Health check response."""
status: str = Field(default="healthy", description="Health status")
model: str = Field(..., description="Current model")
device: str = Field(..., description="Computation device")
ready: bool = Field(default=True, description="Ready for requests")
class ModelInfoResponse(BaseModel):
"""Model information response."""
id: str = Field(..., description="Model ID")
object: str = Field(default="model", description="Object type")
owned_by: str = Field(default="Alibaba", description="Model owner")
supported_languages: List[str] = Field(..., description="Supported languages")
supports_streaming: bool = Field(default=True, description="Supports streaming")
supports_voice_clone: bool = Field(default=True, description="Supports voice cloning")
class ModelsListResponse(BaseModel):
"""List of available models."""
object: str = Field(default="list", description="Object type")
data: List[ModelInfoResponse] = Field(..., description="List of models")
# ============== Voice Management ==============
class VoiceResponse(BaseModel):
"""Custom voice information."""
id: str = Field(..., description="Voice ID")
name: str = Field(..., description="Voice name")
language: str = Field(..., description="Voice language")
created_at: int = Field(..., description="Creation timestamp")
object: str = Field(default="voice", description="Object type")
class VoicesListResponse(BaseModel):
"""List of custom voices."""
object: str = Field(default="list", description="Object type")
data: List[VoiceResponse] = Field(..., description="List of voices")
# ============== Text Validation ==============
class TextValidationRequest(BaseModel):
"""Request to validate text for TTS."""
text: str = Field(..., min_length=1, max_length=10000, description="Text to validate")
language: str = Field(default="English", description="Language for validation")
class TextValidationResponse(BaseModel):
"""Text validation response."""
valid: bool = Field(..., description="Whether text is valid for TTS")
language: str = Field(..., description="Detected language")
character_count: int = Field(..., description="Number of characters")
estimated_duration: float = Field(..., description="Estimated audio duration in seconds")
warnings: List[str] = Field(default_factory=list, description="Any warnings about the text")
# ============== Batch Processing ==============
class BatchJobStatus(str, Enum):
"""Batch job status."""
PENDING = "pending"
PROCESSING = "processing"
COMPLETED = "completed"
FAILED = "failed"
CANCELLED = "cancelled"
class BatchItem(BaseModel):
"""Single item in a batch request."""
text: str = Field(..., min_length=1, description="Text to synthesize")
language: str = Field(default="English", description="Language")
voice_clone_mode: VoiceCloneMode = Field(default=VoiceCloneMode.DISABLED, description="Voice cloning mode")
class CreateBatchRequest(BaseModel):
"""Request to create a batch job."""
items: List[BatchItem] = Field(..., min_items=1, max_items=100, description="Batch items")
model: TTSModel = Field(default=TTSModel.BASE, description="Model to use")
class BatchJobResponse(BaseModel):
"""Batch job information."""
id: str = Field(..., description="Job ID")
object: str = Field(default="batch", description="Object type")
status: BatchJobStatus = Field(..., description="Current status")
created_at: int = Field(..., description="Creation timestamp")
updated_at: int = Field(..., description="Last update timestamp")
request_counts: Dict[str, int] = Field(..., description="Counts: total, processing, completed, failed")
output_file_id: Optional[str] = Field(default=None, description="Output file ID when completed")
class BatchResultItem(BaseModel):
"""Single result item from batch job."""
index: int = Field(..., description="Item index")
status: str = Field(..., description="Item status: success or error")
error: Optional[str] = Field(default=None, description="Error message if failed")
audio_base64: Optional[str] = Field(default=None, description="Generated audio in base64")
duration: Optional[float] = Field(default=None, description="Audio duration")
class BatchResultsResponse(BaseModel):
"""Batch job results."""
job_id: str = Field(..., description="Batch job ID")
object: str = Field(default="batch.results", description="Object type")
status: BatchJobStatus = Field(..., description="Job status")
data: List[BatchResultItem] = Field(..., description="Result items")
# ============== Usage & Quota ==============
class UsageResponse(BaseModel):
"""API usage statistics."""
object: str = Field(default="usage", description="Object type")
requests_made: int = Field(..., description="Total requests made")
audio_generated_seconds: float = Field(..., description="Total audio seconds generated")
audio_generated_minutes: float = Field(..., description="Total audio minutes generated")
requests_by_model: Dict[str, int] = Field(..., description="Requests per model")
requests_by_language: Dict[str, int] = Field(..., description="Requests per language")
class QuotaResponse(BaseModel):
"""Rate limits and quotas."""
object: str = Field(default="quota", description="Object type")
requests_per_minute: int = Field(..., description="Rate limit (requests/minute)")
max_text_length: int = Field(..., description="Maximum text length")
max_batch_size: int = Field(..., description="Maximum batch items")
concurrent_requests: int = Field(..., description="Max concurrent requests")
remaining_requests: int = Field(..., description="Remaining requests in current window")
# ============== Audio Conversion ==============
class AudioFormat(str, Enum):
"""Supported audio formats."""
WAV = "wav"
MP3 = "mp3"
OGG = "ogg"
FLAC = "flac"
class ConvertAudioRequest(BaseModel):
"""Request to convert audio format/sample rate."""
audio_base64: str = Field(..., description="Audio data in base64")
target_format: AudioFormat = Field(default=AudioFormat.WAV, description="Target audio format")
target_sample_rate: Optional[int] = Field(default=None, ge=8000, le=48000, description="Target sample rate (Hz)")
class ConvertAudioResponse(BaseModel):
"""Audio conversion response."""
id: str = Field(..., description="Request ID")
object: str = Field(default="audio", description="Object type")
created: int = Field(..., description="Timestamp")
format: str = Field(..., description="Output format")
sample_rate: int = Field(..., description="Output sample rate")
audio_base64: str = Field(..., description="Converted audio in base64")
duration: float = Field(..., description="Duration in seconds")
# ============== Model Configuration ==============
class ModelConfigResponse(BaseModel):
"""Model configuration details."""
id: str = Field(..., description="Model ID")
object: str = Field(default="model.config", description="Object type")
size: str = Field(..., description="Model size (parameters)")
tokenizer_type: str = Field(..., description="Tokenizer type")
languages: List[str] = Field(..., description="Supported languages")
max_text_length: int = Field(..., description="Maximum input text length")
output_sample_rate: int = Field(..., description="Output sample rate (Hz)")
streaming_supported: bool = Field(default=True, description="Streaming support")
voice_cloning_supported: bool = Field(default=True, description="Voice cloning support")
recommended_parameters: Dict[str, Any] = Field(..., description="Recommended generation parameters")