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:
KeyInfo Bot committed 2026-06-24 11:41:24 +08:00
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
@@ -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)