{% extends "base.html" %}

{% block title %}TTSFM API Documentation{% endblock %}

{% block extra_css %}
<style>
    .code-block {
        background-color: #f8f9fa;
        border: 1px solid #e9ecef;
        border-radius: 0.375rem;
        padding: 1rem;
        margin: 1rem 0;
        overflow-x: auto;
    }
    
    .endpoint-card {
        border-left: 4px solid #007bff;
        margin-bottom: 2rem;
    }
    
    .method-badge {
        font-size: 0.75rem;
        padding: 0.25rem 0.5rem;
        border-radius: 0.25rem;
        font-weight: bold;
        margin-right: 0.5rem;
    }
    
    .method-get { background-color: #28a745; color: white; }
    .method-post { background-color: #007bff; color: white; }
    .method-put { background-color: #ffc107; color: black; }
    .method-delete { background-color: #dc3545; color: white; }
    
    .response-example {
        background-color: #f1f3f4;
        border-radius: 0.375rem;
        padding: 1rem;
        margin-top: 1rem;
    }
    
    .toc {
        position: sticky;
        top: 2rem;
        max-height: calc(100vh - 4rem);
        overflow-y: auto;
    }
    
    .toc a {
        color: #6c757d;
        text-decoration: none;
        display: block;
        padding: 0.25rem 0;
        border-left: 2px solid transparent;
        padding-left: 1rem;
    }
    
    .toc a:hover, .toc a.active {
        color: #007bff;
        border-left-color: #007bff;
    }
</style>
{% endblock %}

{% block content %}
<div class="container py-5">
    <div class="row">
        <div class="col-12 text-center mb-5">
            <h1 class="display-4 fw-bold">
                <i class="fas fa-book me-3 text-primary"></i>API Documentation
            </h1>
            <p class="lead text-muted">
                Complete reference for the TTSFM Text-to-Speech API. Free, simple, and powerful.
            </p>
        </div>
    </div>
    
    <div class="row">
        <!-- Table of Contents -->
        <div class="col-lg-3">
            <div class="toc">
                <h5 class="fw-bold mb-3">Contents</h5>
                <a href="#overview">Overview</a>
                <a href="#authentication">Authentication</a>
                <a href="#text-validation">Text Validation</a>
                <a href="#endpoints">API Endpoints</a>
                <a href="#voices">Voices</a>
                <a href="#formats">Audio Formats</a>
                <a href="#generate">Generate Speech</a>

                <a href="#combined">Combined Audio</a>
                <a href="#status">Status & Health</a>
                <a href="#errors">Error Handling</a>
                <a href="#examples">Code Examples</a>
                <a href="#python-package">Python Package</a>
            </div>
        </div>
        
        <!-- Documentation Content -->
        <div class="col-lg-9">
            <!-- Overview -->
            <section id="overview" class="mb-5">
                <h2 class="fw-bold mb-3">Overview</h2>
                <p>
                    The TTSFM API provides a modern, OpenAI-compatible interface for text-to-speech generation.
                    It supports multiple voices, audio formats, and includes advanced features like text length
                    validation and intelligent auto-combine functionality.
                </p>
                
                <div class="alert alert-info">
                    <i class="fas fa-info-circle me-2"></i>
                    <strong>Base URL:</strong> <code>{{ request.url_root }}api/</code>
                </div>
                
                <h4>Key Features</h4>
                <ul>
                    <li><strong>🎤 11 different voice options</strong> - Choose from alloy, echo, nova, and more</li>
                    <li><strong>🎵 Multiple audio formats</strong> - MP3, WAV, OPUS, AAC, FLAC, PCM support</li>
                    <li><strong>🤖 OpenAI compatibility</strong> - Drop-in replacement for OpenAI's TTS API</li>
                    <li><strong>✨ Auto-combine feature</strong> - Automatically handles long text (>4096 chars) by splitting and combining audio</li>
                    <li><strong>📊 Text length validation</strong> - Smart validation with configurable limits</li>

                    <li><strong>📈 Real-time monitoring</strong> - Status endpoints and health checks</li>
                </ul>

                <div class="alert alert-success">
                    <i class="fas fa-star me-2"></i>
                    <strong>New in v3.2.3:</strong> Enhanced `/v1/audio/speech` endpoint with intelligent auto-combine feature.
                    Streamlined web interface with clean, user-friendly design and automatic long-text handling!
                </div>
            </section>
            
            <!-- Authentication -->
            <section id="authentication" class="mb-5">
                <h2 class="fw-bold mb-3">Authentication</h2>
                <p>
                    Currently, the API supports optional API key authentication. If configured,
                    include your API key in the request headers.
                </p>
                
                <div class="code-block">
                    <pre><code>Authorization: Bearer YOUR_API_KEY</code></pre>
                </div>
            </section>
            
            <!-- Text Validation -->
            <section id="text-validation" class="mb-5">
                <h2 class="fw-bold mb-3">Text Length Validation</h2>
                <p>
                    TTSFM includes built-in text length validation to ensure compatibility with TTS models.
                    The default maximum length is 4096 characters, but this can be customized.
                </p>
                
                <div class="alert alert-warning">
                    <i class="fas fa-exclamation-triangle me-2"></i>
                    <strong>Important:</strong> Text exceeding the maximum length will be rejected unless
                    validation is disabled or the text is split into chunks.
                </div>
                
                <h4>Validation Options</h4>
                <ul>
                    <li><code>max_length</code>: Maximum allowed characters (default: 4096)</li>
                    <li><code>validate_length</code>: Enable/disable validation (default: true)</li>
                    <li><code>preserve_words</code>: Avoid splitting words when chunking (default: true)</li>
                </ul>
            </section>
            
            <!-- API Endpoints -->
            <section id="endpoints" class="mb-5">
                <h2 class="fw-bold mb-3">API Endpoints</h2>
                
                <!-- Voices Endpoint -->
                <div class="card endpoint-card" id="voices">
                    <div class="card-body">
                        <h4 class="card-title">
                            <span class="method-badge method-get">GET</span>
                            /api/voices
                        </h4>
                        <p class="card-text">Get list of available voices.</p>
                        
                        <h6>Response Example:</h6>
                        <div class="response-example">
                            <pre><code>{
  "voices": [
    {
      "id": "alloy",
      "name": "Alloy",
      "description": "Alloy voice"
    },
    {
      "id": "echo",
      "name": "Echo", 
      "description": "Echo voice"
    }
  ],
  "count": 6
}</code></pre>
                        </div>
                    </div>
                </div>
                
                <!-- Formats Endpoint -->
                <div class="card endpoint-card" id="formats">
                    <div class="card-body">
                        <h4 class="card-title">
                            <span class="method-badge method-get">GET</span>
                            /api/formats
                        </h4>
                        <p class="card-text">Get list of supported audio formats.</p>
                        
                        <h6>Response Example:</h6>
                        <div class="response-example">
                            <pre><code>{
  "formats": [
    {
      "id": "mp3",
      "name": "MP3",
      "mime_type": "audio/mp3",
      "description": "MP3 audio format"
    }
  ],
  "count": 6
}</code></pre>
                        </div>
                    </div>
                </div>
                
                <!-- Text Validation Endpoint -->
                <div class="card endpoint-card">
                    <div class="card-body">
                        <h4 class="card-title">
                            <span class="method-badge method-post">POST</span>
                            /api/validate-text
                        </h4>
                        <p class="card-text">Validate text length and get splitting suggestions.</p>
                        
                        <h6>Request Body:</h6>
                        <div class="code-block">
                            <pre><code>{
  "text": "Your text to validate",
  "max_length": 4096
}</code></pre>
                        </div>
                        
                        <h6>Response Example:</h6>
                        <div class="response-example">
                            <pre><code>{
  "text_length": 5000,
  "max_length": 4096,
  "is_valid": false,
  "needs_splitting": true,
  "suggested_chunks": 2,
  "chunk_preview": [
    "First chunk preview...",
    "Second chunk preview..."
  ]
}</code></pre>
                        </div>
                    </div>
                </div>
                
                <!-- Generate Speech Endpoint -->
                <div class="card endpoint-card" id="generate">
                    <div class="card-body">
                        <h4 class="card-title">
                            <span class="method-badge method-post">POST</span>
                            /api/generate
                        </h4>
                        <p class="card-text">Generate speech from text.</p>
                        
                        <h6>Request Body:</h6>
                        <div class="code-block">
                            <pre><code>{
  "text": "Hello, world!",
  "voice": "alloy",
  "format": "mp3",
  "instructions": "Speak cheerfully",
  "max_length": 4096,
  "validate_length": true
}</code></pre>
                        </div>
                        
                        <h6>Parameters:</h6>
                        <ul>
                            <li><code>text</code> (required): Text to convert to speech</li>
                            <li><code>voice</code> (optional): Voice ID (default: "alloy")</li>
                            <li><code>format</code> (optional): Audio format (default: "mp3")</li>
                            <li><code>instructions</code> (optional): Voice modulation instructions</li>
                            <li><code>max_length</code> (optional): Maximum text length (default: 4096)</li>
                            <li><code>validate_length</code> (optional): Enable validation (default: true)</li>
                        </ul>
                        
                        <h6>Response:</h6>
                        <p>Returns audio file with appropriate Content-Type header.</p>
                    </div>
                </div>
                
            </section>

            <!-- Python Package -->
            <section id="python-package" class="mb-5">
                <h3 class="fw-bold mb-4">
                    <i class="fab fa-python me-2 text-warning"></i>Python Package
                </h3>

                <div class="card">
                    <div class="card-body">
                        <h5>Long Text Support</h5>
                        <p>The TTSFM Python package includes built-in long text splitting functionality for developers who need fine-grained control:</p>

                        <div class="code-block">
                            <pre><code>from ttsfm import TTSClient, Voice, AudioFormat

# Create client
client = TTSClient()

# Generate speech from long text (automatically splits into separate files)
responses = client.generate_speech_long_text(
    text="Very long text that exceeds 4096 characters...",
    voice=Voice.ALLOY,
    response_format=AudioFormat.MP3,
    max_length=2000,
    preserve_words=True
)

# Save each chunk as separate files
for i, response in enumerate(responses, 1):
    response.save_to_file(f"part_{i:03d}.mp3")</code></pre>
                        </div>

                        <h6 class="mt-4">Developer Features:</h6>
                        <ul>
                            <li><strong>Manual Splitting:</strong> Full control over text chunking for advanced use cases</li>
                            <li><strong>Word Preservation:</strong> Maintains word boundaries for natural speech</li>
                            <li><strong>Separate Files:</strong> Each chunk saved as individual audio file</li>
                            <li><strong>CLI Support:</strong> Use <code>--split-long-text</code> flag for command-line usage</li>
                        </ul>

                        <div class="alert alert-info">
                            <i class="fas fa-info-circle me-2"></i>
                            <strong>Note:</strong> For web users, the auto-combine feature in <code>/v1/audio/speech</code> is recommended
                            as it automatically handles long text and returns a single seamless audio file.
                        </div>
                    </div>
                </div>

                <!-- Combined Audio Endpoints -->
                <div class="card endpoint-card" id="combined">
                    <div class="card-body">
                        <h4 class="card-title">
                            <span class="method-badge method-post">POST</span>
                            /api/generate-combined
                        </h4>
                        <p class="card-text">Generate a single combined audio file from long text. Automatically splits text into chunks, generates speech for each chunk, and combines them into one seamless audio file.</p>

                        <h6>Request Body:</h6>
                        <div class="code-block">
                            <pre><code>{
  "text": "Very long text that exceeds the limit...",
  "voice": "alloy",
  "format": "mp3",
  "instructions": "Optional voice instructions",
  "max_length": 4096,
  "preserve_words": true
}</code></pre>
                        </div>

                        <h6>Response:</h6>
                        <p>Returns a single audio file containing all chunks combined seamlessly.</p>

                        <h6>Response Headers:</h6>
                        <ul>
                            <li><code>X-Chunks-Combined</code>: Number of chunks that were combined</li>
                            <li><code>X-Original-Text-Length</code>: Original text length in characters</li>
                            <li><code>X-Audio-Size</code>: Final audio file size in bytes</li>
                        </ul>
                    </div>
                </div>

                <!-- OpenAI Compatible Endpoint with Auto-Combine -->
                <div class="card endpoint-card">
                    <div class="card-body">
                        <h4 class="card-title">
                            <span class="method-badge method-post">POST</span>
                            /v1/audio/speech
                        </h4>
                        <p class="card-text">Enhanced OpenAI-compatible endpoint with auto-combine feature. Automatically handles long text by splitting and combining audio chunks when needed.</p>

                        <h6>Request Body:</h6>
                        <div class="code-block">
                            <pre><code>{
  "model": "gpt-4o-mini-tts",
  "input": "Text of any length...",
  "voice": "alloy",
  "response_format": "mp3",
  "instructions": "Optional voice instructions",
  "speed": 1.0,
  "auto_combine": true,
  "max_length": 4096
}</code></pre>
                        </div>

                        <h6>Enhanced Parameters:</h6>
                        <ul>
                            <li><strong>auto_combine</strong> (boolean, default: true):
                                <ul>
                                    <li><code>true</code>: Automatically split long text and combine audio chunks into a single file</li>
                                    <li><code>false</code>: Return error if text exceeds max_length (standard OpenAI behavior)</li>
                                </ul>
                            </li>
                            <li><strong>max_length</strong> (integer, default: 4096): Maximum characters per chunk when splitting</li>
                        </ul>

                        <h6>Response Headers:</h6>
                        <ul>
                            <li><code>X-Auto-Combine</code>: Whether auto-combine was enabled (true/false)</li>
                            <li><code>X-Chunks-Combined</code>: Number of audio chunks combined (1 for short text)</li>
                            <li><code>X-Original-Text-Length</code>: Original text length (for long text processing)</li>
                            <li><code>X-Audio-Format</code>: Audio format of the response</li>
                            <li><code>X-Audio-Size</code>: Audio file size in bytes</li>
                        </ul>

                        <h6>Examples:</h6>
                        <div class="code-block">
                            <pre><code># Short text (works normally)
curl -X POST {{ request.url_root }}v1/audio/speech \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini-tts",
    "input": "Hello world!",
    "voice": "alloy"
  }'

# Long text with auto-combine (default)
curl -X POST {{ request.url_root }}v1/audio/speech \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini-tts",
    "input": "Very long text...",
    "voice": "alloy",
    "auto_combine": true
  }'

# Long text without auto-combine (will error)
curl -X POST {{ request.url_root }}v1/audio/speech \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini-tts",
    "input": "Very long text...",
    "voice": "alloy",
    "auto_combine": false
  }'</code></pre>
                        </div>

                        <div class="alert alert-info mt-3">
                            <i class="fas fa-info-circle me-2"></i>
                            <strong>Audio Combination:</strong> Uses advanced audio processing (PyDub) when available,
                            with intelligent fallbacks for different environments. Supports all audio formats.
                        </div>

                        <h6 class="mt-4">Use Cases:</h6>
                        <ul>
                            <li><strong>Long Articles:</strong> Convert blog posts or articles to single audio files</li>
                            <li><strong>Audiobooks:</strong> Generate chapters as single audio files</li>
                            <li><strong>Podcasts:</strong> Create podcast episodes from scripts</li>
                            <li><strong>Educational Content:</strong> Convert learning materials to audio</li>
                        </ul>

                        <h6 class="mt-4">Example Usage:</h6>
                        <div class="code-block">
                            <pre><code># Python example
import requests

response = requests.post(
    "{{ request.url_root }}api/generate-combined",
    json={
        "text": "Your very long text content here...",
        "voice": "nova",
        "format": "mp3",
        "max_length": 2000
    }
)

if response.status_code == 200:
    with open("combined_audio.mp3", "wb") as f:
        f.write(response.content)

    chunks = response.headers.get('X-Chunks-Combined')
    print(f"Combined {chunks} chunks into single file")</code></pre>
                        </div>
                    </div>
                </div>
            </section>
        </div>
    </div>
</div>
{% endblock %}

{% block extra_js %}
<script>
    // Smooth scrolling for TOC links
    document.querySelectorAll('.toc a').forEach(link => {
        link.addEventListener('click', function(e) {
            e.preventDefault();
            const target = document.querySelector(this.getAttribute('href'));
            if (target) {
                target.scrollIntoView({ behavior: 'smooth' });
                
                // Update active link
                document.querySelectorAll('.toc a').forEach(l => l.classList.remove('active'));
                this.classList.add('active');
            }
        });
    });
    
    // Highlight current section in TOC
    window.addEventListener('scroll', function() {
        const sections = document.querySelectorAll('section[id]');
        const scrollPos = window.scrollY + 100;
        
        sections.forEach(section => {
            const top = section.offsetTop;
            const bottom = top + section.offsetHeight;
            const id = section.getAttribute('id');
            const link = document.querySelector(`.toc a[href="#${id}"]`);
            
            if (scrollPos >= top && scrollPos < bottom) {
                document.querySelectorAll('.toc a').forEach(l => l.classList.remove('active'));
                if (link) link.classList.add('active');
            }
        });
    });
</script>
{% endblock %}
