tts-api / templates /index.html
gavanduffy
Port pocket-tts to supertonic3: 44100 Hz, 10 voices, 31 languages
d715e26
Raw
History Blame Contribute Delete
9.28 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SuperTonic3 - Local TTS</title>
<link rel="stylesheet" href="/static/css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
</head>
<body>
<script>
window.SUPERTONIC3_CONFIG = {
isDocker: {{ 'true' if is_docker else 'false' }}
};
</script>
<div class="container">
<header>
<h1>SuperTonic3</h1>
<p class="subtitle">Local text-to-speech with 31 languages & 10 built-in voices</p>
<p
class="version-strip"
data-server-version="{{ versions.server }}"
data-supertonic3-version="{{ versions.supertonic3 }}"
>
Server v{{ versions.server }}
· supertonic3 v{{ versions.supertonic3 }}
</p>
</header>
<div class="content">
<div class="control-group">
<label for="text-input">Text Prompt</label>
<textarea
id="text-input"
placeholder="Enter text to generate speech..."
>Hello! I am SuperTonic3, running locally on your machine.</textarea>
</div>
<div class="control-group">
<label for="voice-input">Voice Selection</label>
<div class="input-with-action">
<input
id="voice-input"
type="text"
autocomplete="off"
placeholder="Select a voice..."
/>
<button
type="button"
class="clear-btn"
id="voice-clear-btn"
aria-label="Clear voice search"
>
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
<ul
id="voice-list"
class="voice-list"
aria-label="Available voices"
>
</ul>
</div>
<div id="voice-id-display" class="voice-id-helper hidden">
ID: <span class="voice-id-text"></span>
<button
class="copy-btn"
id="voice-id-copy-btn"
title="Copy to clipboard"
>
<svg
width="12"
height="12"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path
d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"
></path>
</svg>
</button>
</div>
</div>
<div class="control-group">
<label for="format-select">Output Format</label>
<select
id="format-select"
style="
width: 100%;
padding: 8px;
border-radius: 4px;
border: 1px solid var(--border-color);
background: var(--input-bg);
color: var(--text-color);
"
>
<option value="mp3">MP3</option>
<option value="opus">Opus</option>
<option value="aac">AAC</option>
<option value="flac">FLAC</option>
<option value="wav" selected>WAV</option>
<option value="pcm">PCM (Raw)</option>
</select>
</div>
<div class="control-group">
<label
for="stream-toggle"
style="display: inline-flex; align-items: center; cursor: pointer"
>
<input
type="checkbox"
id="stream-toggle"
checked
style="width: auto; margin-right: 8px"
/>
Enable Streaming Response
</label>
<p
id="format-info"
style="
font-size: 0.85em;
color: var(--text-secondary);
margin-top: 8px;
line-height: 1.4;
"
></p>
</div>
<button id="generate-btn" class="btn-primary">
<span>Generate Speech</span>
<div class="spinner"></div>
</button>
<div class="output-section" id="output-section">
<audio id="audio-player" controls></audio>
<br />
<a href="#" id="download-btn" class="download-link">Download Audio</a>
</div>
</div>
<div class="api-docs">
<h2>API Documentation</h2>
<p class="api-intro">
OpenAI-compatible TTS API. Use any OpenAI TTS client by pointing it to
this server.
</p>
<div class="endpoint">
<div class="endpoint-header">
<span class="method get">GET</span>
<code class="path">/health</code>
</div>
<p class="endpoint-desc">
Health check endpoint for container orchestration and monitoring.
</p>
<div class="response-example">
<strong>Response:</strong>
<pre>
{
"status": "healthy",
"model_loaded": true,
"sample_rate": 44100
}</pre>
</div>
</div>
<div class="endpoint">
<div class="endpoint-header">
<span class="method get">GET</span>
<code class="path">/v1/voices</code>
</div>
<p class="endpoint-desc">
List all available built-in voices.
</p>
<div class="response-example">
<strong>Response:</strong>
<pre>
{
"object": "list",
"data": [
{"id": "M1", "name": "M1", "object": "voice", "type": "builtin"},
{"id": "F1", "name": "F1", "object": "voice", "type": "builtin"}
]
}</pre>
</div>
</div>
<div class="endpoint">
<div class="endpoint-header">
<span class="method post">POST</span>
<code class="path">/v1/audio/speech</code>
</div>
<p class="endpoint-desc">
Generate speech audio from text. OpenAI-compatible endpoint.
</p>
<div class="params-section">
<strong>Request Body (JSON):</strong>
<table class="params-table">
<thead>
<tr>
<th>Parameter</th>
<th>Type</th>
<th>Required</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>input</code></td>
<td>string</td>
<td></td>
<td>-</td>
<td>The text to generate speech from</td>
</tr>
<tr>
<td><code>voice</code></td>
<td>string</td>
<td></td>
<td><code>M1</code></td>
<td>
Voice ID. See <code>/v1/voices</code>
</td>
</tr>
<tr>
<td><code>model</code></td>
<td>string</td>
<td></td>
<td>-</td>
<td>Ignored (for OpenAI compatibility)</td>
</tr>
<tr>
<td><code>response_format</code></td>
<td>string</td>
<td></td>
<td><code>mp3</code></td>
<td>
Audio format: <code>mp3</code>, <code>opus</code>,
<code>aac</code>, <code>flac</code>, <code>wav</code>,
<code>pcm</code>
</td>
</tr>
<tr>
<td><code>stream</code></td>
<td>boolean</td>
<td></td>
<td><code>false</code></td>
<td>Enable streaming response</td>
</tr>
<tr>
<td><code>lang</code></td>
<td>string</td>
<td></td>
<td><code>en</code></td>
<td>Language code for pronunciation</td>
</tr>
</tbody>
</table>
</div>
<div class="example-section">
<strong>Example Request (curl):</strong>
<pre>
curl -X POST http://localhost:7860/v1/audio/speech \
-H "Content-Type: application/json" \
-d '{
"input": "Hello world!",
"voice": "M1",
"response_format": "mp3"
}' \
--output speech.mp3</pre>
</div>
<div class="example-section">
<strong>Example (Python with OpenAI client):</strong>
<pre>
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:7860/v1",
api_key="not-needed"
)
response = client.audio.speech.create(
model="tts-1",
voice="M1",
input="Hello world!"
)
response.stream_to_file("output.mp3")</pre>
</div>
<div class="response-example">
<strong>Response:</strong>
<p>Audio file in the requested format (binary stream).</p>
<p>
<strong>Content-Type:</strong> <code>audio/mpeg</code>,
<code>audio/wav</code>, <code>audio/opus</code>, etc.
</p>
</div>
<div class="error-section">
<strong>Error Response:</strong>
<pre>
{
"error": "Missing required field: input"
}</pre>
</div>
</div>
<div class="voices-reference">
<h3>Built-in Voices</h3>
<p>10 voices available: M1-M5 (male), F1-F5 (female)</p>
<div class="voice-chips">
<span class="voice-chip">M1</span>
<span class="voice-chip">M2</span>
<span class="voice-chip">M3</span>
<span class="voice-chip">M4</span>
<span class="voice-chip">M5</span>
<span class="voice-chip">F1</span>
<span class="voice-chip">F2</span>
<span class="voice-chip">F3</span>
<span class="voice-chip">F4</span>
<span class="voice-chip">F5</span>
</div>
</div>
</div>
</div>
<script src="/static/js/app.js"></script>
</body>
</html>