diff --git a/backend/main.py b/backend/main.py
index 59fb9e18..9a90bcec 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -34,6 +34,10 @@ app = FastAPI(
title="voicebox API",
description="Production-quality Qwen3-TTS voice cloning API",
version=__version__,
+ servers=[
+ {"url": "http://localhost:8000", "description": "Local development server"},
+ {"url": "http://localhost:17493", "description": "Production server"},
+ ],
)
# CORS middleware
diff --git a/docs2/app/global.css b/docs2/app/global.css
index 25072e9d..30af24fa 100644
--- a/docs2/app/global.css
+++ b/docs2/app/global.css
@@ -2,3 +2,13 @@
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
@import 'fumadocs-openapi/css/preset.css';
+
+:root {
+ --color-fd-primary: hsl(43, 50%, 50%);
+ --color-fd-primary-foreground: hsl(222.2, 47.4%, 11.2%);
+}
+
+.dark {
+ --color-fd-primary: hsl(43, 50%, 45%);
+ --color-fd-primary-foreground: hsl(0, 0%, 95%);
+}
diff --git a/docs2/content/docs/api/authentication.mdx b/docs2/content/docs/api/authentication.mdx
deleted file mode 100644
index e4e72808..00000000
--- a/docs2/content/docs/api/authentication.mdx
+++ /dev/null
@@ -1,55 +0,0 @@
----
-title: "Authentication"
-description: "API authentication and security"
----
-
-## Current Status
-
-
- Authentication is not currently implemented in Voicebox. The API is intended for local use only.
-
-
-## Local Usage
-
-For local development and usage:
-- API runs on `localhost:17493`
-- No authentication required
-- Access restricted to local machine
-
-## Future Implementation
-
-Authentication will be added in a future release for:
-- Remote deployments
-- Multi-user access
-- Production environments
-
-Planned authentication methods:
-- API keys
-- OAuth 2.0
-- JWT tokens
-
-## Security Best Practices
-
-Until authentication is implemented:
-
-
-
- Use WireGuard or Tailscale for remote access
-
-
- Run behind nginx with basic auth
-
-
- Restrict access to trusted IPs only
-
-
- Don't expose to public internet
-
-
-
-## Coming Soon
-
-- API key management
-- User accounts
-- Rate limiting
-- Access control
diff --git a/docs2/content/docs/api/generation.mdx b/docs2/content/docs/api/generation.mdx
deleted file mode 100644
index c9fff59c..00000000
--- a/docs2/content/docs/api/generation.mdx
+++ /dev/null
@@ -1,119 +0,0 @@
----
-title: "Generation API"
-description: "Generate speech from text"
----
-
-## Generate Speech
-
-```http
-POST /generate
-```
-
-**Request:**
-```json
-{
- "text": "Hello world",
- "profile_id": "abc123",
- "language": "en"
-}
-```
-
-**Response:**
-```json
-{
- "id": "gen123",
- "text": "Hello world",
- "profile_id": "abc123",
- "language": "en",
- "audio_url": "/audio/gen123.wav",
- "duration": 2.3,
- "created_at": "2024-01-29T12:00:00Z"
-}
-```
-
-## List History
-
-```http
-GET /history
-```
-
-**Query Parameters:**
-- `profile_id` (optional) - Filter by voice profile
-- `limit` (optional) - Number of results (default: 50)
-- `offset` (optional) - Pagination offset
-
-**Response:**
-```json
-{
- "generations": [
- {
- "id": "gen123",
- "text": "Hello world",
- "profile_id": "abc123",
- "duration": 2.3,
- "created_at": "2024-01-29T12:00:00Z"
- }
- ],
- "total": 100
-}
-```
-
-## Get Generation
-
-```http
-GET /history/{id}
-```
-
-**Response:**
-```json
-{
- "id": "gen123",
- "text": "Hello world",
- "profile_id": "abc123",
- "language": "en",
- "audio_url": "/audio/gen123.wav",
- "duration": 2.3,
- "created_at": "2024-01-29T12:00:00Z"
-}
-```
-
-## Delete Generation
-
-```http
-DELETE /history/{id}
-```
-
-**Response:**
-```json
-{
- "success": true
-}
-```
-
-## TypeScript Example
-
-```typescript
-import { VoiceboxClient } from '@/lib/api'
-
-const client = new VoiceboxClient({
- baseUrl: 'http://localhost:17493'
-})
-
-// Generate speech
-const generation = await client.generate({
- text: 'Hello world',
- profile_id: 'abc123',
- language: 'en'
-})
-
-// Get audio URL
-const audioUrl = generation.audio_url
-
-// List history
-const history = await client.listHistory({
- profile_id: 'abc123',
- limit: 20
-})
-```
-
-For full API documentation, visit `http://localhost:17493/docs` when the server is running.
diff --git a/docs2/content/docs/api/meta.json b/docs2/content/docs/api/meta.json
deleted file mode 100644
index 154992f5..00000000
--- a/docs2/content/docs/api/meta.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "title": "API Reference",
- "pages": [
- "overview",
- "authentication",
- "voice-profiles",
- "generation",
- "recordings"
- ]
-}
diff --git a/docs2/content/docs/api/overview.mdx b/docs2/content/docs/api/overview.mdx
deleted file mode 100644
index c862a332..00000000
--- a/docs2/content/docs/api/overview.mdx
+++ /dev/null
@@ -1,219 +0,0 @@
----
-title: "API Overview"
-description: "Integrate voice synthesis into your applications with the Voicebox REST API"
----
-
-## Introduction
-
-Voicebox exposes a full REST API that allows you to integrate voice synthesis into your own applications. The API runs on `http://localhost:17493` by default.
-
-
- When Voicebox is running, visit the auto-generated API documentation at `http://localhost:17493/docs`
-
-
-## Base URL
-
-```
-http://localhost:17493
-```
-
-For remote deployments, replace `localhost` with your server's IP or hostname.
-
-## Authentication
-
-
- Currently, the API does not require authentication for local development. Authentication will be added in a future release for production deployments.
-
-
-## Quick Example
-
-Here's a simple example of generating speech:
-
-```bash
-# Generate speech
-curl -X POST http://localhost:17493/generate \
- -H "Content-Type: application/json" \
- -d '{
- "text": "Hello world",
- "profile_id": "abc123",
- "language": "en"
- }'
-```
-
-## API Endpoints
-
-The Voicebox API is organized into several categories:
-
-
-
- Create, list, update, and delete voice profiles
-
-
- Generate speech from text using voice profiles
-
-
- Record and transcribe audio
-
-
- Create and manage multi-voice stories (coming soon)
-
-
-
-## Core Endpoints
-
-### Voice Profiles
-
-```http
-GET /profiles # List all profiles
-POST /profiles # Create a new profile
-GET /profiles/{id} # Get profile details
-PUT /profiles/{id} # Update a profile
-DELETE /profiles/{id} # Delete a profile
-POST /profiles/{id}/samples # Add voice sample
-```
-
-### Generation
-
-```http
-POST /generate # Generate speech
-GET /history # List generation history
-GET /history/{id} # Get generation details
-DELETE /history/{id} # Delete from history
-```
-
-### Recordings
-
-```http
-POST /recordings # Start recording
-POST /recordings/stop # Stop recording
-POST /transcribe # Transcribe audio
-```
-
-## Response Format
-
-All API responses follow a consistent JSON format:
-
-```json
-{
- "success": true,
- "data": {
- // Response data
- },
- "error": null
-}
-```
-
-Error responses:
-
-```json
-{
- "success": false,
- "data": null,
- "error": {
- "message": "Error description",
- "code": "ERROR_CODE"
- }
-}
-```
-
-## Data Models
-
-### Voice Profile
-
-```json
-{
- "id": "abc123",
- "name": "John Smith",
- "language": "en",
- "description": "Professional narrator voice",
- "created_at": "2024-01-29T12:00:00Z",
- "samples": [
- {
- "id": "sample123",
- "audio_path": "/path/to/sample.wav",
- "duration": 15.5
- }
- ]
-}
-```
-
-### Generation
-
-```json
-{
- "id": "gen123",
- "text": "Hello world",
- "profile_id": "abc123",
- "language": "en",
- "audio_path": "/path/to/output.wav",
- "duration": 2.3,
- "created_at": "2024-01-29T12:00:00Z"
-}
-```
-
-## TypeScript Client
-
-Voicebox provides an auto-generated TypeScript client with full type safety:
-
-```typescript
-import { VoiceboxClient } from '@/lib/api'
-
-const client = new VoiceboxClient({
- baseUrl: 'http://localhost:17493'
-})
-
-// Create a profile
-const profile = await client.createProfile({
- name: 'John Smith',
- language: 'en'
-})
-
-// Generate speech
-const generation = await client.generate({
- text: 'Hello world',
- profile_id: profile.id,
- language: 'en'
-})
-```
-
-The client is automatically generated from the OpenAPI schema. See [Development Setup](/development/setup#generate-openapi-client) for details.
-
-## Rate Limiting
-
-
- Currently, there are no rate limits for local usage. Rate limiting will be added in a future release for production deployments.
-
-
-## WebSocket Support
-
-
- Real-time streaming generation via WebSockets is planned for a future release.
-
-
-## Use Cases
-
-
-
- Generate dynamic dialogue for NPCs and characters
-
-
- Automate voiceovers for videos and podcasts
-
-
- Build text-to-speech tools for visually impaired users
-
-
- Create custom voice interfaces
-
-
-
-## Next Steps
-
-
-
- Learn how to manage voice profiles
-
-
- Generate speech from text
-
-
diff --git a/docs2/content/docs/api/recordings.mdx b/docs2/content/docs/api/recordings.mdx
deleted file mode 100644
index dd0552d2..00000000
--- a/docs2/content/docs/api/recordings.mdx
+++ /dev/null
@@ -1,95 +0,0 @@
----
-title: "Recordings API"
-description: "Record and transcribe audio"
----
-
-## Start Recording
-
-```http
-POST /recordings/start
-```
-
-**Request:**
-```json
-{
- "source": "microphone"
-}
-```
-
-**Response:**
-```json
-{
- "recording_id": "rec123",
- "status": "recording"
-}
-```
-
-## Stop Recording
-
-```http
-POST /recordings/stop
-```
-
-**Request:**
-```json
-{
- "recording_id": "rec123"
-}
-```
-
-**Response:**
-```json
-{
- "recording_id": "rec123",
- "audio_url": "/audio/rec123.wav",
- "duration": 15.5
-}
-```
-
-## Transcribe Audio
-
-```http
-POST /transcribe
-```
-
-**Request:** (multipart/form-data)
-```
-audio:
-language: "en" (optional)
-```
-
-**Response:**
-```json
-{
- "text": "Transcribed speech text here",
- "language": "en",
- "duration": 15.5,
- "confidence": 0.95
-}
-```
-
-## TypeScript Example
-
-```typescript
-import { VoiceboxClient } from '@/lib/api'
-
-const client = new VoiceboxClient({
- baseUrl: 'http://localhost:17493'
-})
-
-// Start recording
-const recording = await client.startRecording({
- source: 'microphone'
-})
-
-// ... record audio ...
-
-// Stop recording
-const result = await client.stopRecording(recording.id)
-
-// Transcribe
-const transcription = await client.transcribe(audioFile, 'en')
-console.log(transcription.text)
-```
-
-For full API documentation, visit `http://localhost:17493/docs` when the server is running.
diff --git a/docs2/content/docs/api/voice-profiles.mdx b/docs2/content/docs/api/voice-profiles.mdx
deleted file mode 100644
index 3715e44c..00000000
--- a/docs2/content/docs/api/voice-profiles.mdx
+++ /dev/null
@@ -1,149 +0,0 @@
----
-title: "Voice Profiles API"
-description: "Manage voice profiles programmatically"
----
-
-## Endpoints
-
-### List Profiles
-
-```http
-GET /profiles
-```
-
-**Response:**
-```json
-{
- "profiles": [
- {
- "id": "abc123",
- "name": "John Smith",
- "language": "en",
- "description": "Professional narrator",
- "created_at": "2024-01-29T12:00:00Z",
- "sample_count": 2
- }
- ]
-}
-```
-
-### Get Profile
-
-```http
-GET /profiles/{id}
-```
-
-**Response:**
-```json
-{
- "id": "abc123",
- "name": "John Smith",
- "language": "en",
- "description": "Professional narrator",
- "created_at": "2024-01-29T12:00:00Z",
- "samples": [
- {
- "id": "sample123",
- "duration": 15.5,
- "created_at": "2024-01-29T12:00:00Z"
- }
- ]
-}
-```
-
-### Create Profile
-
-```http
-POST /profiles
-```
-
-**Request:**
-```json
-{
- "name": "John Smith",
- "language": "en",
- "description": "Professional narrator"
-}
-```
-
-**Response:**
-```json
-{
- "id": "abc123",
- "name": "John Smith",
- "language": "en",
- "description": "Professional narrator",
- "created_at": "2024-01-29T12:00:00Z"
-}
-```
-
-### Update Profile
-
-```http
-PUT /profiles/{id}
-```
-
-**Request:**
-```json
-{
- "name": "Updated Name",
- "description": "Updated description"
-}
-```
-
-### Delete Profile
-
-```http
-DELETE /profiles/{id}
-```
-
-**Response:**
-```json
-{
- "success": true
-}
-```
-
-### Add Voice Sample
-
-```http
-POST /profiles/{id}/samples
-```
-
-**Request:** (multipart/form-data)
-```
-audio:
-```
-
-**Response:**
-```json
-{
- "sample_id": "sample123",
- "duration": 15.5
-}
-```
-
-## TypeScript Example
-
-```typescript
-import { VoiceboxClient } from '@/lib/api'
-
-const client = new VoiceboxClient({
- baseUrl: 'http://localhost:17493'
-})
-
-// Create profile
-const profile = await client.createProfile({
- name: 'John Smith',
- language: 'en',
- description: 'Professional narrator'
-})
-
-// Add sample
-await client.addSample(profile.id, audioFile)
-
-// List all profiles
-const profiles = await client.listProfiles()
-```
-
-For full API documentation, visit `http://localhost:17493/docs` when the server is running.
diff --git a/docs2/content/docs/developer/contributing.mdx b/docs2/content/docs/developer/contributing.mdx
index d67a2f4b..d14947d4 100644
--- a/docs2/content/docs/developer/contributing.mdx
+++ b/docs2/content/docs/developer/contributing.mdx
@@ -259,7 +259,11 @@ When adding new API endpoints:
- Add documentation in `/docs/api/`
+ The API documentation is automatically generated from the OpenAPI schema. Ensure your endpoint has proper docstrings and type hints, then regenerate the docs:
+
+ ```bash
+ bun run generate:api
+ ```
diff --git a/docs2/content/docs/developer/setup.mdx b/docs2/content/docs/developer/setup.mdx
index c2c44f24..6160868a 100644
--- a/docs2/content/docs/developer/setup.mdx
+++ b/docs2/content/docs/developer/setup.mdx
@@ -208,7 +208,7 @@ This downloads the OpenAPI schema and generates the TypeScript client in `app/sr
Learn how to build production releases
-
+
Explore the REST API
diff --git a/docs2/content/docs/meta.json b/docs2/content/docs/meta.json
index 11ea0c16..043b2aaa 100644
--- a/docs2/content/docs/meta.json
+++ b/docs2/content/docs/meta.json
@@ -2,7 +2,6 @@
"title": "Voicebox Documentation",
"pages": [
"overview",
- "api",
"api-reference",
"developer",
"plans"
diff --git a/docs2/content/docs/overview/quick-start.mdx b/docs2/content/docs/overview/quick-start.mdx
index 6fee0496..b4563d20 100644
--- a/docs2/content/docs/overview/quick-start.mdx
+++ b/docs2/content/docs/overview/quick-start.mdx
@@ -118,7 +118,7 @@ The Stories Editor lets you create multi-voice narratives with a timeline-based
Learn advanced techniques for high-quality voice cloning
-
+
Integrate Voicebox into your own applications
diff --git a/docs2/openapi.json b/docs2/openapi.json
index 8f31bf9e..1a196e6c 100644
--- a/docs2/openapi.json
+++ b/docs2/openapi.json
@@ -1 +1 @@
-{"openapi":"3.1.0","info":{"title":"voicebox API","description":"Production-quality Qwen3-TTS voice cloning API","version":"0.1.0"},"paths":{"/":{"get":{"summary":"Root","description":"Root endpoint.","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health","description":"Health check endpoint.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/profiles":{"get":{"summary":"List Profiles","description":"List all voice profiles.","operationId":"list_profiles_profiles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/VoiceProfileResponse"},"type":"array","title":"Response List Profiles Profiles Get"}}}}}},"post":{"summary":"Create Profile","description":"Create a new voice profile.","operationId":"create_profile_profiles_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceProfileCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/profiles/{profile_id}":{"get":{"summary":"Get Profile","description":"Get a voice profile by ID.","operationId":"get_profile_profiles__profile_id__get","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Update Profile","description":"Update a voice profile.","operationId":"update_profile_profiles__profile_id__put","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceProfileCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Profile","description":"Delete a voice profile.","operationId":"delete_profile_profiles__profile_id__delete","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/profiles/{profile_id}/samples":{"post":{"summary":"Add Profile Sample","description":"Add a sample to a voice profile.","operationId":"add_profile_sample_profiles__profile_id__samples_post","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_add_profile_sample_profiles__profile_id__samples_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileSampleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"Get Profile Samples","description":"Get all samples for a profile.","operationId":"get_profile_samples_profiles__profile_id__samples_get","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProfileSampleResponse"},"title":"Response Get Profile Samples Profiles Profile Id Samples Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/profiles/samples/{sample_id}":{"delete":{"summary":"Delete Profile Sample","description":"Delete a profile sample.","operationId":"delete_profile_sample_profiles_samples__sample_id__delete","parameters":[{"name":"sample_id","in":"path","required":true,"schema":{"type":"string","title":"Sample Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/generate":{"post":{"summary":"Generate Speech","description":"Generate speech from text using a voice profile.","operationId":"generate_speech_generate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/history":{"get":{"summary":"List History","description":"List generation history with optional filters.","operationId":"list_history_history_get","parameters":[{"name":"profile_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile Id"}},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistoryListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/history/{generation_id}":{"get":{"summary":"Get Generation","description":"Get a generation by ID.","operationId":"get_generation_history__generation_id__get","parameters":[{"name":"generation_id","in":"path","required":true,"schema":{"type":"string","title":"Generation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistoryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Generation","description":"Delete a generation.","operationId":"delete_generation_history__generation_id__delete","parameters":[{"name":"generation_id","in":"path","required":true,"schema":{"type":"string","title":"Generation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/history/stats":{"get":{"summary":"Get Stats","description":"Get generation statistics.","operationId":"get_stats_history_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/transcribe":{"post":{"summary":"Transcribe Audio","description":"Transcribe audio file to text.","operationId":"transcribe_audio_transcribe_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_transcribe_audio_transcribe_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscriptionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/audio/{generation_id}":{"get":{"summary":"Get Audio","description":"Serve generated audio file.","operationId":"get_audio_audio__generation_id__get","parameters":[{"name":"generation_id","in":"path","required":true,"schema":{"type":"string","title":"Generation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/models/load":{"post":{"summary":"Load Model","description":"Manually load TTS model.","operationId":"load_model_models_load_post","parameters":[{"name":"model_size","in":"query","required":false,"schema":{"type":"string","default":"1.7B","title":"Model Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/models/unload":{"post":{"summary":"Unload Model","description":"Unload TTS model to free memory.","operationId":"unload_model_models_unload_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/models/progress/{model_name}":{"get":{"summary":"Get Model Progress","description":"Get model download progress via Server-Sent Events.","operationId":"get_model_progress_models_progress__model_name__get","parameters":[{"name":"model_name","in":"path","required":true,"schema":{"type":"string","title":"Model Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/models/status":{"get":{"summary":"Get Model Status","description":"Get status of all available models.","operationId":"get_model_status_models_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelStatusListResponse"}}}}}}},"/models/download":{"post":{"summary":"Trigger Model Download","description":"Trigger download of a specific model.","operationId":"trigger_model_download_models_download_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelDownloadRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"Body_add_profile_sample_profiles__profile_id__samples_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"},"reference_text":{"type":"string","title":"Reference Text"}},"type":"object","required":["file","reference_text"],"title":"Body_add_profile_sample_profiles__profile_id__samples_post"},"Body_transcribe_audio_transcribe_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language"}},"type":"object","required":["file"],"title":"Body_transcribe_audio_transcribe_post"},"GenerationRequest":{"properties":{"profile_id":{"type":"string","title":"Profile Id"},"text":{"type":"string","maxLength":5000,"minLength":1,"title":"Text"},"language":{"type":"string","pattern":"^(en|zh)$","title":"Language","default":"en"},"seed":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Seed"},"model_size":{"anyOf":[{"type":"string","pattern":"^(1\\.7B|0\\.6B)$"},{"type":"null"}],"title":"Model Size","default":"1.7B"}},"type":"object","required":["profile_id","text"],"title":"GenerationRequest","description":"Request model for voice generation."},"GenerationResponse":{"properties":{"id":{"type":"string","title":"Id"},"profile_id":{"type":"string","title":"Profile Id"},"text":{"type":"string","title":"Text"},"language":{"type":"string","title":"Language"},"audio_path":{"type":"string","title":"Audio Path"},"duration":{"type":"number","title":"Duration"},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","profile_id","text","language","audio_path","duration","seed","created_at"],"title":"GenerationResponse","description":"Response model for voice generation."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponse":{"properties":{"status":{"type":"string","title":"Status"},"model_loaded":{"type":"boolean","title":"Model Loaded"},"model_downloaded":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Model Downloaded"},"model_size":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Size"},"gpu_available":{"type":"boolean","title":"Gpu Available"},"vram_used_mb":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Vram Used Mb"}},"type":"object","required":["status","model_loaded","gpu_available"],"title":"HealthResponse","description":"Response model for health check."},"HistoryListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/HistoryResponse"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","total"],"title":"HistoryListResponse","description":"Response model for history list."},"HistoryResponse":{"properties":{"id":{"type":"string","title":"Id"},"profile_id":{"type":"string","title":"Profile Id"},"profile_name":{"type":"string","title":"Profile Name"},"text":{"type":"string","title":"Text"},"language":{"type":"string","title":"Language"},"audio_path":{"type":"string","title":"Audio Path"},"duration":{"type":"number","title":"Duration"},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","profile_id","profile_name","text","language","audio_path","duration","seed","created_at"],"title":"HistoryResponse","description":"Response model for history entry (includes profile name)."},"ModelDownloadRequest":{"properties":{"model_name":{"type":"string","title":"Model Name"}},"type":"object","required":["model_name"],"title":"ModelDownloadRequest","description":"Request model for triggering model download."},"ModelStatus":{"properties":{"model_name":{"type":"string","title":"Model Name"},"display_name":{"type":"string","title":"Display Name"},"downloaded":{"type":"boolean","title":"Downloaded"},"size_mb":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Size Mb"},"loaded":{"type":"boolean","title":"Loaded","default":false}},"type":"object","required":["model_name","display_name","downloaded"],"title":"ModelStatus","description":"Response model for model status."},"ModelStatusListResponse":{"properties":{"models":{"items":{"$ref":"#/components/schemas/ModelStatus"},"type":"array","title":"Models"}},"type":"object","required":["models"],"title":"ModelStatusListResponse","description":"Response model for model status list."},"ProfileSampleResponse":{"properties":{"id":{"type":"string","title":"Id"},"profile_id":{"type":"string","title":"Profile Id"},"audio_path":{"type":"string","title":"Audio Path"},"reference_text":{"type":"string","title":"Reference Text"}},"type":"object","required":["id","profile_id","audio_path","reference_text"],"title":"ProfileSampleResponse","description":"Response model for profile sample."},"TranscriptionResponse":{"properties":{"text":{"type":"string","title":"Text"},"duration":{"type":"number","title":"Duration"}},"type":"object","required":["text","duration"],"title":"TranscriptionResponse","description":"Response model for transcription."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VoiceProfileCreate":{"properties":{"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name"},"description":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Description"},"language":{"type":"string","pattern":"^(en|zh)$","title":"Language","default":"en"}},"type":"object","required":["name"],"title":"VoiceProfileCreate","description":"Request model for creating a voice profile."},"VoiceProfileResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"language":{"type":"string","title":"Language"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","description","language","created_at","updated_at"],"title":"VoiceProfileResponse","description":"Response model for voice profile."}}}}
\ No newline at end of file
+{"openapi":"3.1.0","info":{"title":"voicebox API","description":"Production-quality Qwen3-TTS voice cloning API","version":"0.1.0"},"servers":[{"url":"http://localhost:8000","description":"Local development server"}],"paths":{"/":{"get":{"summary":"Root","description":"Root endpoint.","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health","description":"Health check endpoint.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/profiles":{"get":{"summary":"List Profiles","description":"List all voice profiles.","operationId":"list_profiles_profiles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/VoiceProfileResponse"},"type":"array","title":"Response List Profiles Profiles Get"}}}}}},"post":{"summary":"Create Profile","description":"Create a new voice profile.","operationId":"create_profile_profiles_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceProfileCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/profiles/{profile_id}":{"get":{"summary":"Get Profile","description":"Get a voice profile by ID.","operationId":"get_profile_profiles__profile_id__get","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Update Profile","description":"Update a voice profile.","operationId":"update_profile_profiles__profile_id__put","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceProfileCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Profile","description":"Delete a voice profile.","operationId":"delete_profile_profiles__profile_id__delete","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/profiles/{profile_id}/samples":{"post":{"summary":"Add Profile Sample","description":"Add a sample to a voice profile.","operationId":"add_profile_sample_profiles__profile_id__samples_post","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_add_profile_sample_profiles__profile_id__samples_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileSampleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"Get Profile Samples","description":"Get all samples for a profile.","operationId":"get_profile_samples_profiles__profile_id__samples_get","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProfileSampleResponse"},"title":"Response Get Profile Samples Profiles Profile Id Samples Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/profiles/samples/{sample_id}":{"delete":{"summary":"Delete Profile Sample","description":"Delete a profile sample.","operationId":"delete_profile_sample_profiles_samples__sample_id__delete","parameters":[{"name":"sample_id","in":"path","required":true,"schema":{"type":"string","title":"Sample Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/generate":{"post":{"summary":"Generate Speech","description":"Generate speech from text using a voice profile.","operationId":"generate_speech_generate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/history":{"get":{"summary":"List History","description":"List generation history with optional filters.","operationId":"list_history_history_get","parameters":[{"name":"profile_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile Id"}},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistoryListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/history/{generation_id}":{"get":{"summary":"Get Generation","description":"Get a generation by ID.","operationId":"get_generation_history__generation_id__get","parameters":[{"name":"generation_id","in":"path","required":true,"schema":{"type":"string","title":"Generation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistoryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Generation","description":"Delete a generation.","operationId":"delete_generation_history__generation_id__delete","parameters":[{"name":"generation_id","in":"path","required":true,"schema":{"type":"string","title":"Generation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/history/stats":{"get":{"summary":"Get Stats","description":"Get generation statistics.","operationId":"get_stats_history_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/transcribe":{"post":{"summary":"Transcribe Audio","description":"Transcribe audio file to text.","operationId":"transcribe_audio_transcribe_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_transcribe_audio_transcribe_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscriptionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/audio/{generation_id}":{"get":{"summary":"Get Audio","description":"Serve generated audio file.","operationId":"get_audio_audio__generation_id__get","parameters":[{"name":"generation_id","in":"path","required":true,"schema":{"type":"string","title":"Generation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/models/load":{"post":{"summary":"Load Model","description":"Manually load TTS model.","operationId":"load_model_models_load_post","parameters":[{"name":"model_size","in":"query","required":false,"schema":{"type":"string","default":"1.7B","title":"Model Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/models/unload":{"post":{"summary":"Unload Model","description":"Unload TTS model to free memory.","operationId":"unload_model_models_unload_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/models/progress/{model_name}":{"get":{"summary":"Get Model Progress","description":"Get model download progress via Server-Sent Events.","operationId":"get_model_progress_models_progress__model_name__get","parameters":[{"name":"model_name","in":"path","required":true,"schema":{"type":"string","title":"Model Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/models/status":{"get":{"summary":"Get Model Status","description":"Get status of all available models.","operationId":"get_model_status_models_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelStatusListResponse"}}}}}}},"/models/download":{"post":{"summary":"Trigger Model Download","description":"Trigger download of a specific model.","operationId":"trigger_model_download_models_download_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelDownloadRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"Body_add_profile_sample_profiles__profile_id__samples_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"},"reference_text":{"type":"string","title":"Reference Text"}},"type":"object","required":["file","reference_text"],"title":"Body_add_profile_sample_profiles__profile_id__samples_post"},"Body_transcribe_audio_transcribe_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language"}},"type":"object","required":["file"],"title":"Body_transcribe_audio_transcribe_post"},"GenerationRequest":{"properties":{"profile_id":{"type":"string","title":"Profile Id"},"text":{"type":"string","maxLength":5000,"minLength":1,"title":"Text"},"language":{"type":"string","pattern":"^(en|zh)$","title":"Language","default":"en"},"seed":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Seed"},"model_size":{"anyOf":[{"type":"string","pattern":"^(1\\.7B|0\\.6B)$"},{"type":"null"}],"title":"Model Size","default":"1.7B"}},"type":"object","required":["profile_id","text"],"title":"GenerationRequest","description":"Request model for voice generation."},"GenerationResponse":{"properties":{"id":{"type":"string","title":"Id"},"profile_id":{"type":"string","title":"Profile Id"},"text":{"type":"string","title":"Text"},"language":{"type":"string","title":"Language"},"audio_path":{"type":"string","title":"Audio Path"},"duration":{"type":"number","title":"Duration"},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","profile_id","text","language","audio_path","duration","seed","created_at"],"title":"GenerationResponse","description":"Response model for voice generation."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponse":{"properties":{"status":{"type":"string","title":"Status"},"model_loaded":{"type":"boolean","title":"Model Loaded"},"model_downloaded":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Model Downloaded"},"model_size":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Size"},"gpu_available":{"type":"boolean","title":"Gpu Available"},"vram_used_mb":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Vram Used Mb"}},"type":"object","required":["status","model_loaded","gpu_available"],"title":"HealthResponse","description":"Response model for health check."},"HistoryListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/HistoryResponse"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","total"],"title":"HistoryListResponse","description":"Response model for history list."},"HistoryResponse":{"properties":{"id":{"type":"string","title":"Id"},"profile_id":{"type":"string","title":"Profile Id"},"profile_name":{"type":"string","title":"Profile Name"},"text":{"type":"string","title":"Text"},"language":{"type":"string","title":"Language"},"audio_path":{"type":"string","title":"Audio Path"},"duration":{"type":"number","title":"Duration"},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","profile_id","profile_name","text","language","audio_path","duration","seed","created_at"],"title":"HistoryResponse","description":"Response model for history entry (includes profile name)."},"ModelDownloadRequest":{"properties":{"model_name":{"type":"string","title":"Model Name"}},"type":"object","required":["model_name"],"title":"ModelDownloadRequest","description":"Request model for triggering model download."},"ModelStatus":{"properties":{"model_name":{"type":"string","title":"Model Name"},"display_name":{"type":"string","title":"Display Name"},"downloaded":{"type":"boolean","title":"Downloaded"},"size_mb":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Size Mb"},"loaded":{"type":"boolean","title":"Loaded","default":false}},"type":"object","required":["model_name","display_name","downloaded"],"title":"ModelStatus","description":"Response model for model status."},"ModelStatusListResponse":{"properties":{"models":{"items":{"$ref":"#/components/schemas/ModelStatus"},"type":"array","title":"Models"}},"type":"object","required":["models"],"title":"ModelStatusListResponse","description":"Response model for model status list."},"ProfileSampleResponse":{"properties":{"id":{"type":"string","title":"Id"},"profile_id":{"type":"string","title":"Profile Id"},"audio_path":{"type":"string","title":"Audio Path"},"reference_text":{"type":"string","title":"Reference Text"}},"type":"object","required":["id","profile_id","audio_path","reference_text"],"title":"ProfileSampleResponse","description":"Response model for profile sample."},"TranscriptionResponse":{"properties":{"text":{"type":"string","title":"Text"},"duration":{"type":"number","title":"Duration"}},"type":"object","required":["text","duration"],"title":"TranscriptionResponse","description":"Response model for transcription."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VoiceProfileCreate":{"properties":{"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name"},"description":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Description"},"language":{"type":"string","pattern":"^(en|zh)$","title":"Language","default":"en"}},"type":"object","required":["name"],"title":"VoiceProfileCreate","description":"Request model for creating a voice profile."},"VoiceProfileResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"language":{"type":"string","title":"Language"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","description","language","created_at","updated_at"],"title":"VoiceProfileResponse","description":"Response model for voice profile."}}}}
\ No newline at end of file