Update 易瞳语音转录|设计|克隆|降噪 skill in marketplace
Constraint: Public skills are published only by explicit administrator action unless they are tracked third-party market sources. Confidence: high Scope-risk: narrow Directive: Keep private/internal skills out of the public marketplace and preserve normal incremental market Git history. Tested: Marketplace validation passed.
This commit is contained in:
1 parent
b5012cedbc
commit
0f46963526
28 files changed
+998
-385
No files matched your search
@@ -56,20 +56,32 @@ For Qwen clone, always provide both `text` and `ref_text`.
|
||||
Use JSON for voice design and synthesis:
|
||||
|
||||
```bash
|
||||
curl -X POST "$QWEN3_VOICE_API_BASE_URL/v1/voice/design" \
|
||||
BASE_URL="${QWEN3_VOICE_API_BASE_URL:-https://ades.playones.com}"
|
||||
|
||||
curl -X POST "$BASE_URL/v1/voice/design" \
|
||||
-H "Authorization: Bearer $OPENAI_API_KEY" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"text":"Hello world","instruct":"Warm, calm, natural narration","language":"auto"}' \
|
||||
-d '{"provider":"qwen","text":"Hello world","instruct":"Warm, calm, natural narration","language":"auto","temperature":0.9,"max_tokens":4096,"top_k":50,"top_p":1.0,"repetition_penalty":1.05}' \
|
||||
--output voice_design.wav
|
||||
```
|
||||
|
||||
Use multipart form data for clone, enhancement, denoise, and ASR:
|
||||
|
||||
```bash
|
||||
curl -X POST "$QWEN3_VOICE_API_BASE_URL/v1/voice/clone" \
|
||||
BASE_URL="${QWEN3_VOICE_API_BASE_URL:-https://ades.playones.com}"
|
||||
|
||||
curl -X POST "$BASE_URL/v1/voice/clone" \
|
||||
-H "Authorization: Bearer $OPENAI_API_KEY" \
|
||||
-F 'file=@reference.wav' \
|
||||
-F 'provider=qwen' \
|
||||
-F 'text=This is the cloned sentence.' \
|
||||
-F 'ref_text=Transcript of the reference audio.' \
|
||||
-F 'language=auto' \
|
||||
-F 'temperature=0.9' \
|
||||
-F 'max_tokens=4096' \
|
||||
-F 'top_k=50' \
|
||||
-F 'top_p=1.0' \
|
||||
-F 'repetition_penalty=1.05' \
|
||||
--output voice_clone.wav
|
||||
```
|
||||
|
||||
|
||||
@@ -8,11 +8,7 @@
|
||||
- Auth header: `Authorization: Bearer <key>`
|
||||
- If no key is available, get one from `https://kinfo.playones.com`.
|
||||
- Audio-output media type: `audio/wav`
|
||||
- Local source checkouts are source references only unless the user explicitly asks to run a local service. Historical local start command:
|
||||
|
||||
```bash
|
||||
uv run python -m uvicorn fastapi_voice_design_api:app --host 0.0.0.0 --port 8197
|
||||
```
|
||||
- Local source checkouts are source references only unless the user explicitly asks to run a local service.
|
||||
|
||||
## Endpoint Summary
|
||||
|
||||
@@ -20,13 +16,27 @@ uv run python -m uvicorn fastapi_voice_design_api:app --host 0.0.0.0 --port 8197
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Voice design TTS | `POST` | `/v1/voice/design` | JSON | WAV |
|
||||
| Base TTS synthesis | `POST` | `/v1/voice/synthesize` | JSON | WAV |
|
||||
| Voice clone | `POST` | `/v1/voice/clone` | multipart form or raw audio body plus query fields | WAV |
|
||||
| Speech enhancement | `POST` | `/v1/audio/enhance` | multipart form or raw audio body | WAV |
|
||||
| Denoise alias | `POST` | `/v1/audio/denoise` | multipart form or raw audio body | WAV |
|
||||
| ASR transcription | `POST` | `/v1/asr/transcribe` | multipart form or raw audio body | JSON |
|
||||
| Voice clone | `POST` | `/v1/voice/clone` | multipart form | WAV |
|
||||
| Speech enhancement | `POST` | `/v1/audio/enhance` | multipart form | WAV |
|
||||
| Denoise alias | `POST` | `/v1/audio/denoise` | multipart form | WAV |
|
||||
| ASR transcription | `POST` | `/v1/asr/transcribe` | multipart form | JSON |
|
||||
| Health | `GET` | `/health` | none | JSON |
|
||||
| Models | `GET` | `/models` | none | JSON |
|
||||
|
||||
## Parameter Limits
|
||||
|
||||
- `provider`: `qwen` or `voxcpm2`
|
||||
- `text`: 1 to 4096 characters
|
||||
- `instruct`: 1 to 1024 characters; optional for clone
|
||||
- `temperature`: 0 to 2
|
||||
- `max_tokens`: 1 to 8192
|
||||
- `top_k`: 0 to 1000
|
||||
- `top_p`: 0 to 1
|
||||
- `repetition_penalty`: 0.1 to 2
|
||||
- `cfg_value`: 0 to 10
|
||||
- `inference_timesteps`: 1 to 200
|
||||
- Uploaded audio defaults to a 25 MB and 60 second server-side limit, depending on deployment environment variables.
|
||||
|
||||
## Voice Design
|
||||
|
||||
`POST /v1/voice/design`
|
||||
@@ -55,11 +65,18 @@ Qwen example:
|
||||
|
||||
```bash
|
||||
curl -X POST https://ades.playones.com/v1/voice/design \
|
||||
-H 'Authorization: Bearer $OPENAI_API_KEY' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"provider": "qwen",
|
||||
"text": "Hello world",
|
||||
"instruct": "Warm, calm, natural narration",
|
||||
"language": "auto"
|
||||
"language": "auto",
|
||||
"temperature": 0.9,
|
||||
"max_tokens": 4096,
|
||||
"top_k": 50,
|
||||
"top_p": 1.0,
|
||||
"repetition_penalty": 1.05
|
||||
}' \
|
||||
--output voice_design.wav
|
||||
```
|
||||
@@ -68,6 +85,7 @@ VoxCPM2 example:
|
||||
|
||||
```bash
|
||||
curl -X POST https://ades.playones.com/v1/voice/design \
|
||||
-H 'Authorization: Bearer $OPENAI_API_KEY' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"text": "Hello world",
|
||||
@@ -104,11 +122,17 @@ Example:
|
||||
|
||||
```bash
|
||||
curl -X POST https://ades.playones.com/v1/voice/synthesize \
|
||||
-H 'Authorization: Bearer $OPENAI_API_KEY' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"text": "Hello world",
|
||||
"speaker": "Chelsie",
|
||||
"language": "auto"
|
||||
"language": "auto",
|
||||
"temperature": 0.9,
|
||||
"max_tokens": 4096,
|
||||
"top_k": 50,
|
||||
"top_p": 1.0,
|
||||
"repetition_penalty": 1.05
|
||||
}' \
|
||||
--output synthesize.wav
|
||||
```
|
||||
@@ -117,11 +141,10 @@ curl -X POST https://ades.playones.com/v1/voice/synthesize \
|
||||
|
||||
`POST /v1/voice/clone`
|
||||
|
||||
Use this for cloning from reference audio. Prefer multipart form upload with `file=@reference.wav`.
|
||||
Use this for cloning from reference audio. Send multipart form upload with `file=@reference.wav`.
|
||||
|
||||
Audio input:
|
||||
- `file`: reference audio upload
|
||||
- Alternative: raw audio request body with non-JSON `Content-Type`, with text fields in query params
|
||||
|
||||
Shared fields:
|
||||
- `text`: required output text
|
||||
@@ -158,10 +181,17 @@ Qwen clone example:
|
||||
|
||||
```bash
|
||||
curl -X POST https://ades.playones.com/v1/voice/clone \
|
||||
-H 'Authorization: Bearer $OPENAI_API_KEY' \
|
||||
-F 'file=@reference.wav' \
|
||||
-F 'provider=qwen' \
|
||||
-F 'text=This is the cloned sentence.' \
|
||||
-F 'ref_text=This is the transcript of the reference audio.' \
|
||||
-F 'language=auto' \
|
||||
-F 'temperature=0.9' \
|
||||
-F 'max_tokens=4096' \
|
||||
-F 'top_k=50' \
|
||||
-F 'top_p=1.0' \
|
||||
-F 'repetition_penalty=1.05' \
|
||||
--output voice_clone.wav
|
||||
```
|
||||
|
||||
@@ -169,10 +199,16 @@ VoxCPM2 controllable clone without transcript:
|
||||
|
||||
```bash
|
||||
curl -X POST https://ades.playones.com/v1/voice/clone \
|
||||
-H 'Authorization: Bearer $OPENAI_API_KEY' \
|
||||
-F 'file=@reference.wav' \
|
||||
-F 'text=This is the cloned sentence.' \
|
||||
-F 'instruct=Keep the same speaker identity with a calm delivery.' \
|
||||
-F 'provider=voxcpm2' \
|
||||
-F 'cfg_value=2.0' \
|
||||
-F 'inference_timesteps=10' \
|
||||
-F 'normalize=false' \
|
||||
-F 'denoise=false' \
|
||||
-F 'retry_badcase=true' \
|
||||
--output voxcpm2_controllable_clone.wav
|
||||
```
|
||||
|
||||
@@ -180,10 +216,16 @@ VoxCPM2 Hi-Fi clone with transcript:
|
||||
|
||||
```bash
|
||||
curl -X POST https://ades.playones.com/v1/voice/clone \
|
||||
-H 'Authorization: Bearer $OPENAI_API_KEY' \
|
||||
-F 'file=@reference.wav' \
|
||||
-F 'text=This is the cloned sentence.' \
|
||||
-F 'ref_text=This is the transcript of the reference audio.' \
|
||||
-F 'provider=voxcpm2' \
|
||||
-F 'cfg_value=2.0' \
|
||||
-F 'inference_timesteps=10' \
|
||||
-F 'normalize=false' \
|
||||
-F 'denoise=false' \
|
||||
-F 'retry_badcase=true' \
|
||||
--output voxcpm2_hifi_clone.wav
|
||||
```
|
||||
|
||||
@@ -193,7 +235,7 @@ curl -X POST https://ades.playones.com/v1/voice/clone \
|
||||
|
||||
`POST /v1/audio/denoise`
|
||||
|
||||
These two paths call the same service and return `enhanced.wav`. Use either multipart `file=@noisy.wav` or raw audio body.
|
||||
These two paths call the same service and return `enhanced.wav`. Send multipart form upload with `file=@noisy.wav`.
|
||||
|
||||
Optional:
|
||||
- `chunked`: form or query bool. Accepted truthy values include `1`, `true`, `yes`, `on`; falsy values include `0`, `false`, `no`, `off`.
|
||||
@@ -202,10 +244,22 @@ Example:
|
||||
|
||||
```bash
|
||||
curl -X POST https://ades.playones.com/v1/audio/enhance \
|
||||
-H 'Authorization: Bearer $OPENAI_API_KEY' \
|
||||
-F 'file=@noisy.wav' \
|
||||
-F 'chunked=false' \
|
||||
--output enhanced.wav
|
||||
```
|
||||
|
||||
Denoise alias:
|
||||
|
||||
```bash
|
||||
curl -X POST https://ades.playones.com/v1/audio/denoise \
|
||||
-H 'Authorization: Bearer $OPENAI_API_KEY' \
|
||||
-F 'file=@noisy.wav' \
|
||||
-F 'chunked=false' \
|
||||
--output denoise.wav
|
||||
```
|
||||
|
||||
## ASR Transcription
|
||||
|
||||
`POST /v1/asr/transcribe`
|
||||
@@ -226,7 +280,7 @@ This is not audio generation. It returns JSON:
|
||||
}
|
||||
```
|
||||
|
||||
Input is multipart `file=@speech.wav` or raw audio body.
|
||||
Input is multipart form upload with `file=@speech.wav`.
|
||||
|
||||
Optional fields can be form or query params:
|
||||
- `language`: normalized aliases include `zh`, `zh-cn`, `en`, `ja`, `ko`; default is `English`
|
||||
@@ -240,14 +294,20 @@ Example:
|
||||
|
||||
```bash
|
||||
curl -X POST https://ades.playones.com/v1/asr/transcribe \
|
||||
-F 'file=@speech.wav'
|
||||
-H 'Authorization: Bearer $OPENAI_API_KEY' \
|
||||
-F 'file=@speech.wav' \
|
||||
-F 'language=auto' \
|
||||
-F 'temperature=0.0' \
|
||||
-F 'max_tokens=8192' \
|
||||
-F 'top_k=0' \
|
||||
-F 'top_p=1.0'
|
||||
```
|
||||
|
||||
## Health And Models
|
||||
|
||||
```bash
|
||||
curl https://ades.playones.com/health
|
||||
curl https://ades.playones.com/models
|
||||
curl -H 'Authorization: Bearer $OPENAI_API_KEY' https://ades.playones.com/health
|
||||
curl -H 'Authorization: Bearer $OPENAI_API_KEY' https://ades.playones.com/models
|
||||
```
|
||||
|
||||
Model status keys:
|
||||
@@ -270,6 +330,8 @@ Models are lazy-loaded on first request, so `loaded: false` can be normal before
|
||||
- `400 denoise=true requires VOXCPM2_LOAD_DENOISER=true`: retry with `denoise=false` or reconfigure server.
|
||||
- `501 VOXCPM2_BACKEND=vllm_omni is not implemented in this build`: local ARM Mac path supports `official`.
|
||||
- `503 failed to load ... model`: model package, model id, local weights, or optional `voxcpm` dependency is unavailable.
|
||||
- `504 Gateway Time-out`: the request passed HTTP validation but generation exceeded the gateway timeout. Retry after model warmup, reduce `max_tokens` for short test requests, or inspect server logs.
|
||||
- `500 Internal Server Error`: the request reached the application but failed internally. Re-run with `curl -i` and no `--output` to capture the response body; if the body is only `Internal Server Error`, inspect server logs.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
|
||||
+11
-2
@@ -46,10 +46,19 @@ def log(message: str) -> None:
|
||||
print(message, flush=True)
|
||||
|
||||
|
||||
def request_headers(token: str | None) -> dict[str, str]:
|
||||
def bearer_token(token: str | None) -> str:
|
||||
if not token:
|
||||
raise SystemExit(KEY_HELP)
|
||||
return {"Authorization": f"Bearer {token}"}
|
||||
token = token.strip()
|
||||
if token.lower().startswith("bearer "):
|
||||
token = token[7:].strip()
|
||||
if not token:
|
||||
raise SystemExit(KEY_HELP)
|
||||
return token
|
||||
|
||||
|
||||
def request_headers(token: str | None) -> dict[str, str]:
|
||||
return {"Authorization": f"Bearer {bearer_token(token)}"}
|
||||
|
||||
|
||||
def audio_files(input_dir: Path) -> list[Path]:
|
||||
|
||||
@@ -47,11 +47,20 @@ def bool_value(raw: str | bool | None) -> bool | None:
|
||||
raise argparse.ArgumentTypeError(f"invalid boolean value: {raw}")
|
||||
|
||||
|
||||
def request_headers(token: str | None, extra: dict[str, str] | None = None) -> dict[str, str]:
|
||||
def bearer_token(token: str | None) -> str:
|
||||
if not token:
|
||||
raise SystemExit(KEY_HELP)
|
||||
token = token.strip()
|
||||
if token.lower().startswith("bearer "):
|
||||
token = token[7:].strip()
|
||||
if not token:
|
||||
raise SystemExit(KEY_HELP)
|
||||
return token
|
||||
|
||||
|
||||
def request_headers(token: str | None, extra: dict[str, str] | None = None) -> dict[str, str]:
|
||||
headers = dict(extra or {})
|
||||
headers["Authorization"] = f"Bearer {token}"
|
||||
headers["Authorization"] = f"Bearer {bearer_token(token)}"
|
||||
return headers
|
||||
|
||||
|
||||
@@ -108,10 +117,15 @@ def multipart_body(
|
||||
def add_line(value: str) -> None:
|
||||
chunks.append(value.encode("utf-8"))
|
||||
|
||||
def field_value(value: object) -> str:
|
||||
if isinstance(value, bool):
|
||||
return "true" if value else "false"
|
||||
return str(value)
|
||||
|
||||
for name, value in clean_payload(fields).items():
|
||||
add_line(f"--{boundary}\r\n")
|
||||
add_line(f'Content-Disposition: form-data; name="{name}"\r\n\r\n')
|
||||
add_line(f"{value}\r\n")
|
||||
add_line(f"{field_value(value)}\r\n")
|
||||
|
||||
if file_field and file_path:
|
||||
path = Path(file_path)
|
||||
|
||||
Reference in new issue
Block a user