Appearance
TOOLS: szövegből beszéd (TTS)
Ez a dokumentum az admin TOOLS aszinkron Text-to-Speech API-t írja le. Szöveg → WAV hang (MCP GLC-TTS). Hangpresetek: magyar és angol.
Integration source of truth: OpenAPI / Redoc.
Összefoglaló
| Prefix | /api/v1/tools/tts |
| Auth | JWT Bearer |
| Szerepkör | create/list/audio: EDITOR+; DELETE: TENANT_ADMIN+ |
| Billing | glc_text_to_voice (bemeneti szöveg tokenizálás) |
| Korlát | max 1 aktív TTS job / tenant (409); egyenleg 402 |
| Szöveg | 1–100 000 karakter |
| Speed | 0.3–2.0 (default 1.0) |
Endpointok
| Method | Path | Leírás |
|---|---|---|
| GET | /api/v1/tools/tts/voices | Hanglista (language?, refresh?) |
| POST | /api/v1/tools/tts/jobs | Új job |
| GET | /api/v1/tools/tts/jobs | Lista |
| GET | /api/v1/tools/tts/jobs/{job_id} | Státusz (DB-only) |
| GET | /api/v1/tools/tts/jobs/{job_id}/audio | WAV letöltés (ha kész) |
| DELETE | /api/v1/tools/tts/jobs/{job_id} | Törlés (TENANT_ADMIN+) |
Státuszok
QUEUED → MCP_QUEUED → MCP_RUNNING → FINALIZING → COMPLETED | FAILED
Create body
json
{
"text": "Szöveg, amit fel szeretnél olvastatni.",
"voice_id": "pattila",
"speed": 1.0,
"title": "Demo",
"language": "hu"
}A voice_id a GET /voices listából jön (pl. magyar / angol presetek). A nyelv tipikusan a hangpresetet követi.
Példa: hangok → job → poll → audio
Python
python
import time
import requests
BASE_URL = "https://<your-api-host>"
JWT = "your-jwt-token"
headers = {"Authorization": f"Bearer {JWT}", "Content-Type": "application/json"}
# 1) voices
voices = requests.get(
f"{BASE_URL}/api/v1/tools/tts/voices",
headers=headers,
params={"refresh": "1"},
).json()
voice_id = voices.get("default_voice_id") or voices["voices"][0]["id"]
print("voice_id:", voice_id)
# 2) create
r = requests.post(
f"{BASE_URL}/api/v1/tools/tts/jobs",
headers=headers,
json={
"text": "Üdvözöljük a GLC-RAG szövegből beszéd demójában.",
"voice_id": voice_id,
"speed": 1.0,
"title": "Demo TTS",
"language": "hu",
},
)
r.raise_for_status()
job_id = r.json()["job_id"]
# 3) poll
while True:
st = requests.get(f"{BASE_URL}/api/v1/tools/tts/jobs/{job_id}", headers=headers).json()
status = st.get("status")
print(status, st.get("progress_pct"))
if status in ("COMPLETED", "FAILED"):
break
time.sleep(2)
# 4) download WAV
if status == "COMPLETED":
audio = requests.get(
f"{BASE_URL}/api/v1/tools/tts/jobs/{job_id}/audio",
headers={"Authorization": f"Bearer {JWT}"},
)
audio.raise_for_status()
with open("out.wav", "wb") as f:
f.write(audio.content)
print("saved out.wav", len(audio.content), "bytes")TypeScript
typescript
const BASE_URL = "https://<your-api-host>";
const JWT = "your-jwt-token";
const headers = {
Authorization: `Bearer ${JWT}`,
"Content-Type": "application/json",
};
const voices = await fetch(`${BASE_URL}/api/v1/tools/tts/voices?refresh=1`, {
headers,
}).then((r) => r.json());
const voiceId = voices.default_voice_id ?? voices.voices[0].id;
const created = await fetch(`${BASE_URL}/api/v1/tools/tts/jobs`, {
method: "POST",
headers,
body: JSON.stringify({
text: "Hello from GLC-RAG text-to-speech.",
voice_id: voiceId,
speed: 1.0,
title: "Demo EN",
language: "en",
}),
}).then((r) => r.json());
let status = created.status as string;
const jobId = created.job_id as string;
while (status !== "COMPLETED" && status !== "FAILED") {
await new Promise((r) => setTimeout(r, 2000));
const st = await fetch(`${BASE_URL}/api/v1/tools/tts/jobs/${jobId}`, { headers }).then((r) =>
r.json(),
);
status = st.status;
}
if (status === "COMPLETED") {
const blob = await fetch(`${BASE_URL}/api/v1/tools/tts/jobs/${jobId}/audio`, {
headers: { Authorization: `Bearer ${JWT}` },
}).then((r) => r.blob());
console.log("audio bytes", blob.size);
}cURL
bash
BASE_URL="https://<your-api-host>"
JWT="your-jwt-token"
curl -sS "$BASE_URL/api/v1/tools/tts/voices?refresh=1" \
-H "Authorization: Bearer $JWT"
curl -sS -X POST "$BASE_URL/api/v1/tools/tts/jobs" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{"text":"Üdvözlet a demóból.","voice_id":"VOICE_ID","speed":1.0,"language":"hu"}'
curl -sS "$BASE_URL/api/v1/tools/tts/jobs/JOB_ID" \
-H "Authorization: Bearer $JWT"
curl -sS "$BASE_URL/api/v1/tools/tts/jobs/JOB_ID/audio" \
-H "Authorization: Bearer $JWT" \
-o out.wavPHP
php
<?php
$BASE_URL = "https://<your-api-host>";
$JWT = "your-jwt-token";
function http_json(string $method, string $url, string $jwt, ?array $body = null): array {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer $jwt",
"Content-Type: application/json",
],
]);
if ($body !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
}
$raw = curl_exec($ch);
curl_close($ch);
return json_decode($raw, true) ?: [];
}
$voices = http_json("GET", "$BASE_URL/api/v1/tools/tts/voices?refresh=1", $JWT);
$voiceId = $voices["default_voice_id"] ?? ($voices["voices"][0]["id"] ?? null);
$created = http_json("POST", "$BASE_URL/api/v1/tools/tts/jobs", $JWT, [
"text" => "Üdvözlet a demóból.",
"voice_id" => $voiceId,
"speed" => 1.0,
"language" => "hu",
]);
$jobId = $created["job_id"];
do {
sleep(2);
$st = http_json("GET", "$BASE_URL/api/v1/tools/tts/jobs/$jobId", $JWT);
$status = $st["status"] ?? "";
} while ($status !== "COMPLETED" && $status !== "FAILED");
if ($status === "COMPLETED") {
$ch = curl_init("$BASE_URL/api/v1/tools/tts/jobs/$jobId/audio");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $JWT"],
]);
$bin = curl_exec($ch);
curl_close($ch);
file_put_contents("out.wav", $bin);
echo "saved out.wav\n";
}Hibák
| Kód | Jelentés |
|---|---|
| 401 / 403 | Auth / szerepkör |
| 402 | Nincs egyenleg |
| 409 | Aktív job már fut |
| 404 | Audio még nincs / job hiányzik |
| 502 | Hanglista / MCP hiba |
Kapcsolódó
- 56-tools-stt.md – beszédből szöveg
- Admin UI: TOOLS → Szövegből beszéd
- Séma:
scripts/migration/022_tools_tts.sql - Marketing:
/tools-beszed