<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>{{ title }} - {{ html_title }}</title>
    <link rel="icon" href="/tool/speakr/static/img/favicon.ico" type="image/svg+xml">
    <!-- All dependencies bundled locally for offline support -->
    <script src="/tool/speakr/static/vendor/js/tailwind.min.js"></script>
    <!-- All dependencies bundled locally for offline support -->
    <link rel="stylesheet" href="/tool/speakr/static/vendor/css/fontawesome.min.css">
    <link rel="stylesheet" href="/tool/speakr/static/css/styles.css">
    <script src="/tool/speakr/static/js/i18n.js"></script>

    <!-- Loading overlay to prevent FOUC -->
    {% include 'includes/loading_overlay.html' %}
    <script src="/tool/speakr/static/js/loading.js"></script>

    <script>
        // Initialize i18n
        let t = (key) => key; // Default fallback

        async function initializeI18n(language) {
            const userLanguage = language || "{{ user_language }}";

            // Initialize the global i18n instance
            if (window.i18n) {
                await window.i18n.init(userLanguage);

                // Create a shorthand translation function
                t = (key, params) => window.i18n.t(key, params);

                // Update all elements with data-i18n attribute
                document.querySelectorAll('[data-i18n]').forEach(el => {
                    const key = el.getAttribute('data-i18n');
                    el.textContent = t(key);
                });

                // Update all elements with data-i18n-placeholder attribute
                document.querySelectorAll('[data-i18n-placeholder]').forEach(el => {
                    const key = el.getAttribute('data-i18n-placeholder');
                    el.placeholder = t(key);
                });
            }
        }

        // Function to update all UI elements after language change
        function updateAllUIElements() {
            // Update all elements with data-i18n attribute
            document.querySelectorAll('[data-i18n]').forEach(el => {
                const key = el.getAttribute('data-i18n');
                el.textContent = t(key);
            });

            // Update all elements with data-i18n-placeholder attribute
            document.querySelectorAll('[data-i18n-placeholder]').forEach(el => {
                const key = el.getAttribute('data-i18n-placeholder');
                el.placeholder = t(key);
            });

            // Update language options in dropdown to show native names
            const langSelect = document.getElementById('ui_language');
            if (langSelect) {
                const langOptions = {
                    'en': 'English',
                    'es': 'Español (Spanish)',
                    'fr': 'Français (French)',
                    'zh': '中文 (Chinese)',
                    'de': 'Deutsch (German)'
                };

                Array.from(langSelect.options).forEach(option => {
                    if (langOptions[option.value]) {
                        option.textContent = langOptions[option.value];
                    }
                });
            }

            // Force update any Vue or dynamic content by dispatching a custom event
            window.dispatchEvent(new CustomEvent('language-changed', { detail: { language: window.i18n.currentLanguage } }));
        }

        // Function to change language immediately
        async function changeLanguageImmediately(newLanguage) {
            try {
                // Show loading indicator
                const uiLanguageSelect = document.getElementById('ui_language');
                uiLanguageSelect.disabled = true;

                // Add a loading message
                const originalText = uiLanguageSelect.parentElement.querySelector('p').textContent;
                const loadingMsg = uiLanguageSelect.parentElement.querySelector('p');
                if (loadingMsg) {
                    loadingMsg.textContent = 'Applying language change...';
                }

                // Get CSRF token
                const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');

                // Create form data with just the language change
                const formData = new FormData();
                formData.append('csrf_token', csrfToken);
                formData.append('user_name', document.getElementById('user_name').value || '');
                formData.append('user_job_title', document.getElementById('user_job_title').value || '');
                formData.append('user_company', document.getElementById('user_company').value || '');
                formData.append('ui_language', newLanguage);
                formData.append('transcription_language', document.getElementById('transcription_language').value || '');
                formData.append('output_language', document.getElementById('output_language').value || '');

                // Send AJAX request to update language preference
                const response = await fetch('/tool/speakr/account', {
                    method: 'POST',
                    headers: {
                        'X-Requested-With': 'XMLHttpRequest',
                        'X-CSRFToken': csrfToken
                    },
                    body: formData
                });

                if (!response.ok) {
                    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
                }

                // Store the new language in localStorage for other pages
                localStorage.setItem('preferredLanguage', newLanguage);
                localStorage.setItem('ui_language_changed', 'true');

                // Store current tab to restore after reload
                const activeTab = document.querySelector('.tab-link.border-\\[var\\(--border-accent\\)\\]');
                if (activeTab) {
                    const tabName = activeTab.getAttribute('onclick')?.match(/show(\w+)Tab/)?.[1]?.toLowerCase();
                    if (tabName) {
                        localStorage.setItem('activeAccountTab', tabName);
                    }
                }

                // Reload the page to apply the new language completely
                // This ensures all server-side rendered content is also updated
                window.location.reload();

            } catch (error) {
                console.error('Error updating language:', error);
                alert('Failed to update language. Please try again.');
                // Revert the dropdown to previous value if update failed
                document.getElementById('ui_language').value = currentUILanguage;
                document.getElementById('ui_language').disabled = false;

                // Restore original text if loading message was shown
                const loadingMsg = document.getElementById('ui_language').parentElement.querySelector('p');
                if (loadingMsg) {
                    loadingMsg.textContent = originalText;
                }
            }
        }

        // Function to apply the theme based on localStorage
        function applyTheme() {
            // Guard against early execution
            if (!document.documentElement) return;

            // Apply dark mode
            const savedMode = localStorage.getItem('darkMode');
            const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
            if (savedMode === 'true' || (savedMode === null && prefersDark)) {
                document.documentElement.classList.add('dark');
            } else {
                document.documentElement.classList.remove('dark');
            }

            // Apply color scheme
            const savedScheme = localStorage.getItem('colorScheme') || 'blue';
            const isDark = document.documentElement.classList.contains('dark');
            const themePrefix = isDark ? 'theme-dark-' : 'theme-light-';

            // Remove all other theme classes
            const themeClasses = ['blue', 'emerald', 'purple', 'rose', 'amber', 'teal'];
            themeClasses.forEach(theme => {
                document.documentElement.classList.remove(`theme-light-${theme}`);
                document.documentElement.classList.remove(`theme-dark-${theme}`);
            });

            // Add the correct theme class
            if (savedScheme !== 'blue') {
                document.documentElement.classList.add(themePrefix + savedScheme);
            }
        }
        applyTheme();
    </script>
    <style>
        /* Make the page take full height */
        html,
        body {
            height: 100%;
            margin: 0;
            padding: 0;
        }

        /* Container layout for full height */
        .main-container {
            min-height: 100vh;
            display: flex;
            flex-direction: column;
        }

        /* Tab content area with fixed height and scrolling */
        .tab-content-wrapper {
            height: calc(100vh - 280px);
            /* Adjust based on header and tab nav height */
            overflow-y: auto;
            overflow-x: hidden;
        }

        @media (max-width: 640px) {
            .tab-content-wrapper {
                height: calc(100vh - 320px);
                /* Slightly less height on mobile */
            }
        }

        /* Ensure all tab content divs take full height */
        .tab-content {
            min-height: 100%;
            display: flex;
            flex-direction: column;
        }

        /* Custom scrollbar for content areas */
        .tab-content-wrapper::-webkit-scrollbar {
            width: 8px;
        }

        .tab-content-wrapper::-webkit-scrollbar-track {
            background: transparent;
        }

        .tab-content-wrapper::-webkit-scrollbar-thumb {
            background-color: var(--border-secondary);
            border-radius: 4px;
        }

        .tab-content-wrapper::-webkit-scrollbar-thumb:hover {
            background-color: var(--border-accent);
        }

        /* Horizontal scrollbar for tab navigation */
        .tab-nav {
            scrollbar-width: thin;
            scrollbar-color: var(--border-secondary) transparent;
        }

        .tab-nav::-webkit-scrollbar {
            height: 6px;
        }

        .tab-nav::-webkit-scrollbar-track {
            background: transparent;
        }

        .tab-nav::-webkit-scrollbar-thumb {
            background-color: var(--border-secondary);
            border-radius: 3px;
        }

        .tab-nav::-webkit-scrollbar-thumb:hover {
            background-color: var(--border-accent);
        }



        /* Custom scrollbar styling for Speakers Management */
        #content-speakers .overflow-y-auto::-webkit-scrollbar {
            width: 8px;
        }

        #content-speakers .overflow-y-auto::-webkit-scrollbar-track {
            background: transparent;
            border-radius: 4px;
        }

        #content-speakers .overflow-y-auto::-webkit-scrollbar-thumb {
            background-color: var(--border-secondary);
            border-radius: 4px;
            transition: background-color 0.2s;
        }

        #content-speakers .overflow-y-auto::-webkit-scrollbar-thumb:hover {
            background-color: var(--border-accent);
        }

        /* Ensure the content fits properly */
        #content-speakers {
            container-type: inline-size;
        }

        /* Responsive grid adjustments */
        @container (max-width: 640px) {
            #speakersTabGrid {
                grid-template-columns: 1fr;
            }
        }

        @container (min-width: 641px) and (max-width: 768px) {
            #speakersTabGrid {
                grid-template-columns: repeat(2, 1fr);
            }
        }

        @container (min-width: 769px) and (max-width: 1024px) {
            #speakersTabGrid {
                grid-template-columns: repeat(3, 1fr);
            }
        }

        @container (min-width: 1025px) {
            #speakersTabGrid {
                grid-template-columns: repeat(4, 1fr);
            }
        }

        /* Hide scrollbar for tabs */
        .scrollbar-hide {
            -ms-overflow-style: none;
            scrollbar-width: none;
        }

        .scrollbar-hide::-webkit-scrollbar {
            display: none;
        }
    </style>
</head>

<body class="bg-[var(--bg-primary)] text-[var(--text-primary)]">
    <div class="main-container container mx-auto px-4 sm:px-6 lg:px-8 py-6">
        <header class="flex justify-between items-center mb-6 pb-4 border-b border-[var(--border-primary)]">
            <h1 class="text-3xl font-bold text-[var(--text-primary)]">
                <a href="/tool/speakr" class="flex items-center">
                    <img src="/tool/speakr/static/img/icon-192x192.png" alt="{{ html_title }} Logo" class="h-9 w-9 mr-2">
                    {{ html_title }}
                </a>
            </h1>
            <div class="flex items-center space-x-2">
                <button id="darkModeToggle"
                    class="p-2 rounded-full text-[var(--text-muted)] hover:bg-[var(--bg-tertiary)] dark:text-gray-400 dark:hover:bg-gray-700 transition-colors duration-200">
                    <i id="darkModeIcon" class="fas fa-moon"></i>
                </button>
                <div class="relative" id="userDropdown">
                    <button id="userDropdownButton"
                        class="flex items-center px-3 py-2 border border-[var(--border-secondary)] rounded-lg text-[var(--text-secondary)] hover:text-[var(--text-accent)] focus:outline-none">
                        <i class="fas fa-user mr-2"></i>
                        <span>{{ current_user.username }}</span>
                        <i class="fas fa-chevron-down ml-2"></i>
                    </button>
                    <div id="userDropdownMenu"
                        class="hidden absolute right-0 mt-2 w-48 bg-[var(--bg-secondary)] border border-[var(--border-primary)] rounded-lg shadow-lg z-10">
                        <a href="/tool/speakr"
                            class="block px-4 py-2 text-[var(--text-secondary)] hover:bg-[var(--bg-tertiary)] hover:text-[var(--text-accent)]">
                            <i class="fas fa-home mr-2"></i> <span data-i18n="nav.home">Home</span>
                        </a>
                        <a href="/tool/speakr/account"
                            class="block px-4 py-2 text-[var(--text-accent)] bg-[var(--bg-accent)]">
                            <i class="fas fa-user-circle mr-2"></i> <span data-i18n="nav.account">Account</span>
                        </a>
                        {% if current_user.is_admin %}
                        <a href="/tool/speakr/admin"
                            class="block px-4 py-2 text-[var(--text-secondary)] hover:bg-[var(--bg-tertiary)] hover:text-[var(--text-accent)]">
                            <i class="fas fa-user-shield mr-2"></i> <span data-i18n="nav.admin">Admin</span>
                        </a>
                        {% endif %}
                        <a href="/tool/speakr/logout"
                            class="block px-4 py-2 text-[var(--text-secondary)] hover:bg-[var(--bg-tertiary)] hover:text-[var(--text-danger)]">
                            <i class="fas fa-sign-out-alt mr-2"></i> <span data-i18n="nav.signOut">Logout</span>
                        </a>
                    </div>
                </div>
            </div>
        </header>

        <main class="flex-grow flex flex-col">
            <div
                class="bg-[var(--bg-secondary)] rounded-xl shadow-lg border border-[var(--border-primary)] flex flex-col flex-grow overflow-hidden">
                <div class="border-b border-[var(--border-primary)]">
                    <div class="relative">
                        <!-- Scroll gradient indicators -->
                        <div class="absolute left-0 top-0 bottom-0 w-12 bg-gradient-to-r from-[var(--bg-secondary)] to-transparent z-[1] pointer-events-none opacity-0 transition-opacity duration-200 flex items-center justify-start"
                            id="left-scroll-indicator">
                            <i class="fas fa-chevron-left text-[var(--text-muted)] ml-1"></i>
                        </div>
                        <div class="absolute right-0 top-0 bottom-0 w-12 bg-gradient-to-l from-[var(--bg-secondary)] to-transparent z-[1] pointer-events-none opacity-100 transition-opacity duration-200 flex items-center justify-end"
                            id="right-scroll-indicator">
                            <i class="fas fa-chevron-right text-[var(--text-muted)] mr-1"></i>
                        </div>

                        <nav class="tab-nav px-1 sm:px-4 lg:px-6 pt-3 sm:pt-4 lg:pt-6 pb-4 sm:pb-6 -mb-px overflow-x-auto scrollbar-hide"
                            aria-label="Tabs" id="tabs-container">
                            <div class="inline-flex gap-1 sm:gap-2">
                                <a href="#" id="tab-account"
                                    class="inline-flex items-center whitespace-nowrap py-1 px-1.5 sm:py-3 sm:px-3 border-b-2 font-medium text-xs sm:text-sm border-[var(--border-accent)] text-[var(--text-accent)] rounded-t-md sm:rounded-t-lg hover:bg-[var(--bg-tertiary)]">
                                    <i class="fas fa-user-circle mr-0.5 sm:mr-2 text-xs sm:text-sm"></i><span
                                        data-i18n="account.title">Account</span>
                                </a>
                                <a href="#" id="tab-prompts"
                                    class="inline-flex items-center whitespace-nowrap py-1 px-1.5 sm:py-3 sm:px-3 border-b-2 font-medium text-xs sm:text-sm border-transparent text-[var(--text-muted)] hover:text-[var(--text-secondary)] hover:border-[var(--border-secondary)] rounded-t-md sm:rounded-t-lg hover:bg-[var(--bg-tertiary)]">
                                    <i class="fas fa-cog mr-0.5 sm:mr-2 text-xs sm:text-sm"></i><span
                                        data-i18n="accountTabs.promptOptions">Prompts</span>
                                </a>
                                <a href="#" id="tab-shares"
                                    class="inline-flex items-center whitespace-nowrap py-1 px-1.5 sm:py-3 sm:px-3 border-b-2 font-medium text-xs sm:text-sm border-transparent text-[var(--text-muted)] hover:text-[var(--text-secondary)] hover:border-[var(--border-secondary)] rounded-t-md sm:rounded-t-lg hover:bg-[var(--bg-tertiary)]">
                                    <i class="fas fa-share-alt mr-0.5 sm:mr-2 text-xs sm:text-sm"></i><span
                                        data-i18n="accountTabs.sharedTranscripts">Shares</span>
                                </a>
                                <a href="#" id="tab-speakers"
                                    class="inline-flex items-center whitespace-nowrap py-1 px-1.5 sm:py-3 sm:px-3 border-b-2 font-medium text-xs sm:text-sm border-transparent text-[var(--text-muted)] hover:text-[var(--text-secondary)] hover:border-[var(--border-secondary)] rounded-t-md sm:rounded-t-lg hover:bg-[var(--bg-tertiary)]">
                                    <i class="fas fa-users mr-0.5 sm:mr-2 text-xs sm:text-sm"></i><span
                                        data-i18n="accountTabs.speakersManagement">Speakers</span>
                                </a>
                                <a href="#" id="tab-tags"
                                    class="inline-flex items-center whitespace-nowrap py-1 px-1.5 sm:py-3 sm:px-3 border-b-2 font-medium text-xs sm:text-sm border-transparent text-[var(--text-muted)] hover:text-[var(--text-secondary)] hover:border-[var(--border-secondary)] rounded-t-md sm:rounded-t-lg hover:bg-[var(--bg-tertiary)]">
                                    <i class="fas fa-tags mr-0.5 sm:mr-2 text-xs sm:text-sm"></i><span
                                        data-i18n="accountTabs.tagManagement">Tags</span>
                                </a>
                                <a href="#" id="tab-voiceprint"
                                    class="inline-flex items-center whitespace-nowrap py-1 px-1.5 sm:py-3 sm:px-3 border-b-2 font-medium text-xs sm:text-sm border-transparent text-[var(--text-muted)] hover:text-[var(--text-secondary)] hover:border-[var(--border-secondary)] rounded-t-md sm:rounded-t-lg hover:bg-[var(--bg-tertiary)]">
                                    <i class="fas fa-tags mr-0.5 sm:mr-2 text-xs sm:text-sm"></i><span>声纹</span>
                                </a>
                                <a href="#" id="tab-templates"
                                    class="inline-flex items-center whitespace-nowrap py-1 px-1.5 sm:py-3 sm:px-3 border-b-2 font-medium text-xs sm:text-sm border-transparent text-[var(--text-muted)] hover:text-[var(--text-secondary)] hover:border-[var(--border-secondary)] rounded-t-md sm:rounded-t-lg hover:bg-[var(--bg-tertiary)]">
                                    <i class="fas fa-file-alt mr-0.5 sm:mr-2 text-xs sm:text-sm"></i><span
                                        data-i18n="accountTabs.transcriptTemplates">Templates</span>
                                </a>
                                <a href="#" id="tab-about"
                                    class="inline-flex items-center whitespace-nowrap py-1 px-1.5 sm:py-3 sm:px-3 border-b-2 font-medium text-xs sm:text-sm border-transparent text-[var(--text-muted)] hover:text-[var(--text-secondary)] hover:border-[var(--border-secondary)] rounded-t-md sm:rounded-t-lg hover:bg-[var(--bg-tertiary)]">
                                    <i class="fas fa-info-circle mr-0.5 sm:mr-2 text-xs sm:text-sm"></i><span
                                        data-i18n="accountTabs.about">About</span>
                                </a>
                            </div>
                        </nav>
                    </div>
                </div>

                <div class="tab-content-wrapper px-4 sm:px-6 lg:px-8 pb-4 sm:pb-6 lg:pb-8">
                    <div id="content-account" class="tab-content pt-6">
                        <h2 class="text-2xl font-semibold text-[var(--text-primary)] mb-6" data-i18n="account.title">
                            Account Information</h2>
                        {% with messages = get_flashed_messages(with_categories=true) %}
                        {% if messages %}
                        {% for category, message in messages %}
                        <div
                            class="mb-4 p-3 rounded-lg {% if category == 'success' %}bg-[var(--bg-success-light)] text-[var(--text-success-strong)]{% elif category == 'danger' %}bg-[var(--bg-danger-light)] text-[var(--text-danger-strong)]{% else %}bg-[var(--bg-info-light)] text-[var(--text-info-strong)]{% endif %}">
                            {{ message }}
                        </div>
                        {% endfor %}
                        {% endif %}
                        {% endwith %}

                        <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
                            <!-- Left Column: Form -->
                            <div>
                                <form id="accountInfoForm" method="POST" action="/tool/speakr/account"
                                    class="space-y-6">
                                    <div class="mb-6">
                                        <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
                                        <h3 class="text-lg font-medium text-[var(--text-secondary)] mb-2"
                                            data-i18n="account.personalInfo">Personal Information</h3>
                                        <div
                                            class="bg-[var(--bg-tertiary)] p-4 rounded-lg border border-[var(--border-primary)] space-y-4">
                                            <div>
                                                <label for="user_name"
                                                    class="block text-sm font-medium text-[var(--text-muted)]"
                                                    data-i18n="account.fullName">Full Name</label>
                                                <input type="text" name="user_name" id="user_name"
                                                    value="{{ current_user.name or '' }}"
                                                    data-i18n-placeholder="form.yourFullName"
                                                    class="mt-1 block w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md shadow-sm focus:outline-none focus:ring-[var(--border-focus)] focus:border-[var(--border-focus)] sm:text-sm bg-[var(--bg-input)] text-[var(--text-primary)]">
                                            </div>
                                            <div>
                                                <label for="user_job_title"
                                                    class="block text-sm font-medium text-[var(--text-muted)]"
                                                    data-i18n="account.jobTitle">Job Title</label>
                                                <input type="text" name="user_job_title" id="user_job_title"
                                                    value="{{ current_user.job_title or '' }}"
                                                    placeholder="e.g., Software Engineer"
                                                    class="mt-1 block w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md shadow-sm focus:outline-none focus:ring-[var(--border-focus)] focus:border-[var(--border-focus)] sm:text-sm bg-[var(--bg-input)] text-[var(--text-primary)]">
                                            </div>
                                            <div>
                                                <label for="user_company"
                                                    class="block text-sm font-medium text-[var(--text-muted)]"
                                                    data-i18n="account.companyOrganization">Company /
                                                    Organization</label>
                                                <input type="text" name="user_company" id="user_company"
                                                    value="{{ current_user.company or '' }}"
                                                    placeholder="e.g., Acme Corp"
                                                    class="mt-1 block w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md shadow-sm focus:outline-none focus:ring-[var(--border-focus)] focus:border-[var(--border-focus)] sm:text-sm bg-[var(--bg-input)] text-[var(--text-primary)]">
                                            </div>
                                        </div>
                                    </div>

                                    <div class="mb-6">
                                        <h3 class="text-lg font-medium text-[var(--text-secondary)] mb-2"
                                            data-i18n="account.languagePreferences">Language Preferences</h3>
                                        <div
                                            class="bg-[var(--bg-tertiary)] p-4 rounded-lg border border-[var(--border-primary)] space-y-4">
                                            <div>
                                                <label for="ui_language"
                                                    class="block text-sm font-medium text-[var(--text-muted)]"
                                                    data-i18n="account.interfaceLanguage">Interface Language</label>
                                                <select name="ui_language" id="ui_language"
                                                    class="mt-1 block w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md shadow-sm focus:outline-none focus:ring-[var(--border-focus)] focus:border-[var(--border-focus)] sm:text-sm bg-[var(--bg-input)] text-[var(--text-primary)]">
                                                    <option value="en" {% if current_user.ui_language=='en' or not
                                                        current_user.ui_language %}selected{% endif %}>English</option>
                                                    <option value="zh" {% if current_user.ui_language=='zh' %}selected{%
                                                        endif %}>中文 (Chinese)</option>
                                                    <option value="de" {% if current_user.ui_language=='de' %}selected{%
                                                        endif %}>Deutsch (German)</option>
                                                    <option value="es" {% if current_user.ui_language=='es' %}selected{%
                                                        endif %}>Español (Spanish)</option>
                                                    <option value="fr" {% if current_user.ui_language=='fr' %}selected{%
                                                        endif %}>Français (French)</option>
                                                </select>
                                                <p class="text-xs text-[var(--text-light)] mt-1"
                                                    data-i18n="account.chooseLanguageForInterface">Choose the language
                                                    for the application interface.</p>
                                            </div>
                                            <div>
                                                <label for="transcription_language"
                                                    class="block text-sm font-medium text-[var(--text-muted)]"
                                                    data-i18n="account.transcriptionLanguage">转录语言</label>
                                                <input type="text" name="transcription_language"
                                                    id="transcription_language"
                                                    value="{{ current_user.transcription_language or '' }}"
                                                    placeholder="e.g., en, es, zh (ISO 639-1 code)"
                                                    class="mt-1 block w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md shadow-sm focus:outline-none focus:ring-[var(--border-focus)] focus:border-[var(--border-focus)] sm:text-sm bg-[var(--bg-input)] text-[var(--text-primary)]">
                                                <p class="text-xs text-[var(--text-light)] mt-1"
                                                    data-i18n="account.leaveBlankForAutoDetect">Leave blank for
                                                    auto-detection by transcription service.</p>
                                            </div>
                                            <div>
                                                <label for="output_language"
                                                    class="block text-sm font-medium text-[var(--text-muted)]"
                                                    data-i18n="account.preferredOutputLanguage">Preferred Output
                                                    Language</label>
                                                <input type="text" name="output_language" id="output_language"
                                                    value="{{ current_user.output_language or '' }}"
                                                    placeholder="e.g., English, Spanish, Chinese"
                                                    class="mt-1 block w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md shadow-sm focus:outline-none focus:ring-[var(--border-focus)] focus:border-[var(--border-focus)] sm:text-sm bg-[var(--bg-input)] text-[var(--text-primary)]">
                                                <p class="text-xs text-[var(--text-light)] mt-1"
                                                    data-i18n="account.languageForSummaries">Language for titles,
                                                    summaries, and chat. Leave blank for default (default behavior of
                                                    your chosen model).</p>
                                            </div>
                                        </div>
                                    </div>
                                    {% if current_user.is_admin %}
                                    <div class="mb-6">
                                        <h3 class="text-lg font-medium text-[var(--text-secondary)] mb-2">热词配置</h3>
                                        <div
                                            class="bg-[var(--bg-tertiary)] p-4 rounded-lg border border-[var(--border-primary)] space-y-4">

                                            <div>
                                                <label for="transcription_language"
                                                    class="block text-sm font-medium text-[var(--text-muted)]">热词</label>
                                                <textarea name="hot-textarea"
                                                    style="height: 120px;margin-top: 10px;border-radius: 0.375rem;"
                                                    class="hot-textarea w-full  p-2 border border-[var(--border-primary)] rounded-md bg-[var(--bg-secondary)] text-[var(--text-primary)] resize-none overflow-y-auto"></textarea>
                                                <!-- <input type="text" name="transcription_language" id="transcription_language" value="{{ current_user.transcription_language or '' }}" placeholder="请输入热词" class="mt-1 block w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md shadow-sm focus:outline-none focus:ring-[var(--border-focus)] focus:border-[var(--border-focus)] sm:text-sm bg-[var(--bg-input)] text-[var(--text-primary)]"> -->
                                                <p class="text-xs text-[var(--text-light)] mt-1">一行一个，权重用空格隔开，如 "阿里巴巴 20
                                                </p>
                                            </div>

                                        </div>
                                    </div>
                                    <div class="mb-6">
                                        <div class="flex items-center justify-between gap-3 mb-2 flex-wrap">
                                            <div class="flex items-center gap-3 flex-wrap">
                                                <h3 class="text-lg font-medium text-[var(--text-secondary)]">标准词映射</h3>
                                                <span id="standardWordMappingsCount"
                                                    class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-[var(--bg-secondary)] text-[var(--text-muted)] border border-[var(--border-primary)]">
                                                    0 条
                                                </span>
                                            </div>
                                            <div class="flex items-center gap-2 flex-wrap">
                                                <button type="button" id="toggleStandardWordImportPanel"
                                                    class="inline-flex items-center px-3 py-2 text-sm rounded-md border border-[var(--border-primary)] text-[var(--text-secondary)] hover:bg-[var(--bg-secondary)] transition-colors duration-200">
                                                    <i class="fas fa-file-import mr-2"></i>批量导入
                                                </button>
                                                <button type="button" id="copyStandardWordMappingsText"
                                                    class="inline-flex items-center px-3 py-2 text-sm rounded-md border border-[var(--border-primary)] text-[var(--text-secondary)] hover:bg-[var(--bg-secondary)] transition-colors duration-200">
                                                    <i class="fas fa-copy mr-2"></i>复制文本
                                                </button>
                                                <button type="button" id="clearAllStandardWordMappings"
                                                    class="inline-flex items-center px-3 py-2 text-sm rounded-md border border-[var(--text-danger)] text-[var(--text-danger)] hover:bg-[var(--bg-danger)] hover:text-[var(--text-button)] transition-colors duration-200">
                                                    <i class="fas fa-trash-alt mr-2"></i>批量删除
                                                </button>
                                                <button type="button" id="addStandardWordMappingRow"
                                                    class="inline-flex items-center px-3 py-2 text-sm rounded-md bg-[var(--bg-button)] text-[var(--text-button)] hover:bg-[var(--bg-button-hover)] transition-colors duration-200">
                                                    <i class="fas fa-plus mr-2"></i>新增映射
                                                </button>
                                            </div>
                                        </div>
                                        <div
                                            class="bg-[var(--bg-tertiary)] p-4 rounded-lg border border-[var(--border-primary)] space-y-4">
                                            <div id="standardWordImportPanel"
                                                class="hidden rounded-lg border border-dashed border-[var(--border-primary)] bg-[var(--bg-secondary)] p-4 space-y-3">
                                                <div class="flex items-center justify-between gap-3 flex-wrap">
                                                    <div>
                                                        <p class="text-sm font-medium text-[var(--text-secondary)]">批量导入映射</p>
                                                        <p class="text-xs text-[var(--text-light)] mt-1">支持每行一个映射，格式：标准词：常用词1、常用词2</p>
                                                    </div>
                                                    <button type="button" id="closeStandardWordImportPanel"
                                                        class="inline-flex items-center px-2.5 py-1.5 text-xs rounded-md border border-[var(--border-primary)] text-[var(--text-secondary)] hover:bg-[var(--bg-tertiary)] transition-colors duration-200">
                                                        收起
                                                    </button>
                                                </div>
                                                <textarea id="standardWordMappingsBulkInput"
                                                    style="height: 120px;border-radius: 0.375rem;"
                                                    class="w-full p-3 border border-[var(--border-primary)] rounded-md bg-[var(--bg-input)] text-[var(--text-primary)] resize-y"
                                                    placeholder="例如：&#10;OpenAI：欧喷AI、欧彭AI&#10;Whisper：威士博 威士吧"></textarea>
                                                <div class="flex items-center gap-2 flex-wrap">
                                                    <button type="button" id="replaceStandardWordMappingsFromBulk"
                                                        class="inline-flex items-center px-3 py-2 text-sm rounded-md bg-[var(--bg-button)] text-[var(--text-button)] hover:bg-[var(--bg-button-hover)] transition-colors duration-200">
                                                        覆盖导入
                                                    </button>
                                                    <button type="button" id="appendStandardWordMappingsFromBulk"
                                                        class="inline-flex items-center px-3 py-2 text-sm rounded-md border border-[var(--border-primary)] text-[var(--text-secondary)] hover:bg-[var(--bg-tertiary)] transition-colors duration-200">
                                                        追加导入
                                                    </button>
                                                    <button type="button" id="clearStandardWordMappingsBulkInput"
                                                        class="inline-flex items-center px-3 py-2 text-sm rounded-md border border-[var(--border-primary)] text-[var(--text-secondary)] hover:bg-[var(--bg-tertiary)] transition-colors duration-200">
                                                        清空
                                                    </button>
                                                </div>
                                            </div>
                                            <div
                                                class="hidden md:grid grid-cols-[110px_minmax(0,1fr)_minmax(0,2fr)_150px] gap-3 px-4 py-2 rounded-md border border-[var(--border-primary)] bg-[var(--bg-secondary)] text-xs font-medium uppercase tracking-wide text-[var(--text-light)]">
                                                <div>排序</div>
                                                <div>标准词</div>
                                                <div>常用词</div>
                                                <div>操作</div>
                                            </div>
                                            <div id="standardWordMappingsList" class="space-y-2"></div>
                                            <div id="standardWordMappingsEmpty"
                                                class="text-sm text-[var(--text-light)] bg-[var(--bg-secondary)] border border-dashed border-[var(--border-primary)] rounded-md px-4 py-3">
                                                暂无映射。点击“新增映射”后，填写标准词和对应的常用词。
                                            </div>
                                            <p class="text-xs text-[var(--text-light)]">
                                                一个标准词可对应多个常用词；常用词之间可使用顿号“、”或空格分隔。例如：OpenAI → 欧喷AI、欧彭AI
                                            </p>
                                        </div>
                                    </div>
                                    <div class="mb-6">
                                        <h3 class="text-lg font-medium text-[var(--text-secondary)] mb-2">换行配置</h3>
                                        <div
                                            class="bg-[var(--bg-tertiary)] p-4 rounded-lg border border-[var(--border-primary)] space-y-4">

                                            <div>
                                                <label for="transcription_language"
                                                    class="block text-sm font-medium text-[var(--text-muted)]">关键词</label>
                                                <textarea name="handle-textarea"
                                                    style="height: 120px;margin-top: 10px;border-radius: 0.375rem;"
                                                    class="handle-textarea w-full  p-2 border border-[var(--border-primary)] rounded-md bg-[var(--bg-secondary)] text-[var(--text-primary)] resize-none overflow-y-auto"></textarea>
                                                <!-- <input type="text" name="transcription_language" id="transcription_language" value="{{ current_user.transcription_language or '' }}" placeholder="请输入热词" class="mt-1 block w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md shadow-sm focus:outline-none focus:ring-[var(--border-focus)] focus:border-[var(--border-focus)] sm:text-sm bg-[var(--bg-input)] text-[var(--text-primary)]"> -->
                                                <p class="text-xs text-[var(--text-light)] mt-1">
                                                    关键词使用逗号隔开,例如“报告完毕,发言完毕,.*席报告”
                                                </p>
                                            </div>

                                        </div>
                                    </div>
                                    {% endif %}
                                    <div class="mb-6">
                                        <h3
                                            class="text-lg font-medium text-[var(--text-secondary)] mb-2 flex items-center gap-3">
                                            提示词
                                            <button id="openPromptModal"
                                            type="button"
                                                class="px-2 py-1 text-sm bg-blue-500 text-white rounded">选择提示词</button>
                                        </h3>


                                        <div
                                            class="bg-[var(--bg-tertiary)] p-4 rounded-lg border border-[var(--border-primary)] space-y-4">
                                            <div>
                                                <label for="transcription_language"
                                                    class="block text-sm font-medium text-[var(--text-muted)]">提示词</label>
                                                <textarea name="handle-prompt" id="promptTextarea"
                                                readonly
                                                    style="height: 120px;margin-top: 10px;border-radius: 0.375rem;"
                                                    class="handle-prompt w-full p-2 border border-[var(--border-primary)] rounded-md bg-[var(--bg-secondary)] text-[var(--text-primary)] resize-none overflow-y-auto"></textarea>
                                                <p class="text-xs text-[var(--text-light)] mt-1">
                                                    点击上方按钮选择提示词，如果不选择使用默认提示词。</p>
                                            </div>
                                        </div>
                                    </div>


                                    <!-- 弹框 Modal -->
                                    <div id="promptModal"
                                        class="fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex justify-center items-center">

                                        <div
                                            class="bg-[#1f2937] text-white w-1/2 p-6 rounded-lg shadow-xl border border-gray-600">
                                            <h3 class="text-xl font-semibold mb-4">选择提示词</h3>

                                      <div class="bg-[#111827] p-3 rounded max-h-72 overflow-y-auto text-white">

  <!-- 表头 -->
  <div class="grid grid-cols-[50px_350px] px-2 py-2 border-b border-gray-600 text-sm font-semibold">
    <div class="text-center">选择</div>
    <div>提示词</div>
  </div>

  <!-- 表体 -->
  <div id="promptList" class="space-y-2 mt-2"></div>
</div>

                                            <div class="flex justify-end mt-4 gap-3">
                                                <button id="cancelPrompt" type="button"
                                                    class="px-4 py-2 bg-gray-500 rounded hover:bg-gray-600">取消</button>
                                                <button id="confirmPrompt" type="button"
                                                    class="px-4 py-2 bg-blue-600 rounded hover:bg-blue-700">确定</button>
                                            </div>
                                        </div>
                                    </div>
                                    <button type="submit"
                                        class="w-full inline-flex items-center justify-center px-4 py-2 bg-[var(--bg-button)] text-[var(--text-button)] rounded-md hover:bg-[var(--bg-button-hover)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--border-focus)] transition-colors duration-200">
                                        <i class="fas fa-save mr-2"></i> <span
                                            data-i18n="account.saveAllPreferences">Save All Preferences</span>
                                    </button>
                                </form>
                            </div>

                            <!-- Right Column: Stats, User Details, Account Actions -->
                            <div class="space-y-6">
                                <div>
                                    <h3 class="text-lg font-medium text-[var(--text-secondary)] mb-2"
                                        data-i18n="account.statistics">Account Statistics</h3>
                                    <div
                                        class="bg-[var(--bg-tertiary)] p-4 rounded-lg border border-[var(--border-primary)]">
                                        <div class="grid grid-cols-2 gap-4">
                                            <div
                                                class="text-center p-4 bg-[var(--bg-secondary)] rounded-lg border border-[var(--border-primary)] shadow-sm">
                                                <span class="block text-3xl font-bold text-[var(--text-accent)]">{{
                                                    current_user.recordings|length }}</span>
                                                <span class="block text-sm text-[var(--text-muted)]"
                                                    data-i18n="account.totalRecordings">Total Recordings</span>
                                            </div>

                                            <div
                                                class="text-center p-4 bg-[var(--bg-secondary)] rounded-lg border border-[var(--border-primary)] shadow-sm">
                                                <span class="block text-3xl font-bold text-[var(--text-accent)]">
                                                    {% set completed_count =
                                                    current_user.recordings|selectattr('status', 'equalto',
                                                    'COMPLETED')|list|length %}
                                                    {{ completed_count }}
                                                </span>
                                                <span class="block text-sm text-[var(--text-muted)]"
                                                    data-i18n="account.completedRecordings">Completed</span>
                                            </div>

                                            <div
                                                class="text-center p-4 bg-[var(--bg-secondary)] rounded-lg border border-[var(--border-primary)] shadow-sm">
                                                <span class="block text-3xl font-bold text-[var(--text-warn-strong)]">
                                                    {% set processing_count =
                                                    current_user.recordings|selectattr('status', 'in', ['PENDING',
                                                    'PROCESSING', 'SUMMARIZING'])|list|length %}
                                                    {{ processing_count }}
                                                </span>
                                                <span class="block text-sm text-[var(--text-muted)]"
                                                    data-i18n="account.processingRecordings">Processing</span>
                                            </div>

                                            <div
                                                class="text-center p-4 bg-[var(--bg-secondary)] rounded-lg border border-[var(--border-primary)] shadow-sm">
                                                <span class="block text-3xl font-bold text-[var(--text-danger)]">
                                                    {% set failed_count = current_user.recordings|selectattr('status',
                                                    'equalto', 'FAILED')|list|length %}
                                                    {{ failed_count }}
                                                </span>
                                                <span class="block text-sm text-[var(--text-muted)]"
                                                    data-i18n="account.failedRecordings">Failed</span>
                                            </div>
                                        </div>
                                    </div>
                                </div>

                                <div class="mt-6"> <!-- Added mt-6 for spacing, was mb-6 on User Details -->
                                    <h3 class="text-lg font-medium text-[var(--text-secondary)] mb-2"
                                        data-i18n="account.userDetails">User Details</h3>
                                    <div
                                        class="bg-[var(--bg-tertiary)] p-4 rounded-lg border border-[var(--border-primary)]">
                                        <div class="mb-3">
                                            <span class="block text-sm font-medium text-[var(--text-muted)]"
                                                data-i18n="account.username">Username</span>
                                            <span class="block text-[var(--text-primary)]">{{ current_user.username
                                                }}</span>
                                        </div>
                                        <div class="mb-3">
                                            <span
                                                class="block text-sm font-medium text-[var(--text-muted)]">Email</span>
                                            <span class="block text-[var(--text-primary)]">{{ current_user.email
                                                }}</span>
                                        </div>
                                    </div>
                                </div>

                                <div class="mt-6"> <!-- Added mt-6 for spacing, was mt-8 on Account Actions -->
                                    <h3 class="text-lg font-medium text-[var(--text-secondary)] mb-2"
                                        data-i18n="account.accountActions">Account Actions</h3>
                                    <div class="flex flex-col space-y-3">
                                        <a href="/tool/speakr"
                                            class="inline-flex items-center px-4 py-2 bg-[var(--bg-button)] text-[var(--text-button)] rounded-md hover:bg-[var(--bg-button-hover)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--border-focus)] transition-colors duration-200">
                                            <i class="fas fa-microphone mr-2"></i> <span
                                                data-i18n="account.goToRecordings">Go to Recordings</span>
                                        </a>
                                        <button id="changePasswordBtn"
                                            class="inline-flex items-center px-4 py-2 border border-[var(--border-secondary)] text-[var(--text-secondary)] rounded-md hover:bg-[var(--bg-tertiary)] hover:text-[var(--text-accent)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--border-focus)] transition-colors duration-200">
                                            <i class="fas fa-key mr-2"></i> <span
                                                data-i18n="account.changePassword">Change Password</span>
                                        </button>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>

                    <div id="content-prompts" class="hidden tab-content pt-6">
                        <h2 class="text-2xl font-semibold text-[var(--text-primary)] mb-6"
                            data-i18n="accountTabs.promptOptions">Prompt Options</h2>

                        <form id="customPromptsForm" method="POST" action="/tool/speakr/account" class="space-y-6">
                            <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />

                            <!-- Event Extraction Settings -->
                            <div class="bg-[var(--bg-tertiary)] p-6 rounded-lg border border-[var(--border-primary)]">
                                <h3 class="text-lg font-medium text-[var(--text-secondary)] mb-4">
                                    <i class="fas fa-calendar-alt mr-2"></i>
                                    <span data-i18n="eventExtraction.title">Event Extraction</span>
                                </h3>

                                <div class="mb-4">
                                    <label class="flex items-start space-x-3">
                                        <input type="checkbox" name="extract_events" id="extract_events" {% if
                                            current_user.extract_events %}checked{% endif %}
                                            class="mt-1 h-4 w-4 text-[var(--border-accent)] focus:ring-[var(--border-focus)] border-[var(--border-secondary)] rounded">
                                        <div>
                                            <span class="block text-sm font-medium text-[var(--text-primary)]"
                                                data-i18n="eventExtraction.enableLabel">
                                                Enable automatic event extraction from transcripts
                                            </span>
                                            <span class="block text-xs text-[var(--text-muted)] mt-1"
                                                data-i18n="eventExtraction.description">
                                                When enabled, the AI will identify meetings, appointments, and deadlines
                                                mentioned in your recordings and create downloadable calendar events.
                                            </span>
                                        </div>
                                    </label>
                                </div>

                                <div
                                    class="mt-4 p-3 bg-[var(--bg-info-light)] text-[var(--text-info-strong)] rounded-lg text-sm">
                                    <i class="fas fa-info-circle mr-1"></i>
                                    <span data-i18n="eventExtraction.info">
                                        Extracted events will appear in a new "Events" tab on recordings where calendar
                                        items are detected.
                                    </span>
                                </div>
                            </div>

                            <!-- Custom Prompts Section -->
                            <div class="bg-[var(--bg-tertiary)] p-6 rounded-lg border border-[var(--border-primary)]">
                                <h3 class="text-lg font-medium text-[var(--text-secondary)] mb-4"
                                    data-i18n="customPrompts.summaryGeneration">Summary Generation Prompt</h3>

                                <div class="mb-4">
                                    <label for="summary_prompt_custom"
                                        class="block text-sm font-medium text-[var(--text-muted)] mb-2">
                                        <span data-i18n="customPrompts.yourCustomPrompt">Your Custom Summary
                                            Prompt</span>
                                    </label>
                                    <textarea name="summary_prompt" id="summary_prompt_custom" rows="8"
                                        placeholder="Describe how you want your summaries structured. Leave blank to use the admin's default prompt."
                                        data-i18n-placeholder="customPrompts.promptPlaceholder"
                                        class="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md shadow-sm focus:outline-none focus:ring-[var(--border-focus)] focus:border-[var(--border-focus)] sm:text-sm bg-[var(--bg-input)] text-[var(--text-primary)]">{{ current_user.summary_prompt or '' }}</textarea>
                                    <p class="text-xs text-[var(--text-light)] mt-2">
                                        <span data-i18n="customPrompts.promptDescription">This prompt will be used to
                                            generate summaries for your transcriptions. It overrides the admin's default
                                            prompt.</span>
                                    </p>
                                </div>

                                <div
                                    class="mt-6 p-4 bg-[var(--bg-secondary)] rounded-lg border border-[var(--border-secondary)]">
                                    <h4 class="text-sm font-semibold text-[var(--text-accent)] mb-2">
                                        <i class="fas fa-info-circle mr-1"></i>
                                        <span data-i18n="customPrompts.currentDefaultPrompt">Current Default Prompt
                                            (Used if you leave the above blank)</span>
                                    </h4>
                                    <div
                                        class="bg-[var(--bg-primary)] p-3 rounded border border-[var(--border-primary)]">
                                        <pre
                                            class="text-xs text-[var(--text-muted)] whitespace-pre-wrap">{{ default_summary_prompt_text }}</pre>
                                    </div>
                                </div>

                                <div class="mt-4">
                                    <details class="cursor-pointer">
                                        <summary
                                            class="text-sm text-[var(--text-accent)] hover:text-[var(--text-accent-hover)]">
                                            <i class="fas fa-question-circle mr-1"></i>
                                            <span data-i18n="customPrompts.tipsTitle">Tips for Writing Effective
                                                Prompts</span>
                                        </summary>
                                        <div
                                            class="mt-3 p-3 bg-[var(--bg-info-light)] text-[var(--text-info-strong)] rounded-lg text-sm">
                                            <ul class="list-disc list-inside space-y-1">
                                                <li data-i18n="customPrompts.tip1">Be specific about the sections you
                                                    want in your summary</li>
                                                <li data-i18n="customPrompts.tip2">Use clear formatting instructions
                                                    (e.g., "Use bullet points", "Create numbered lists")</li>
                                                <li data-i18n="customPrompts.tip3">Specify if you want certain
                                                    information prioritized</li>
                                                <li data-i18n="customPrompts.tip4">The system will automatically provide
                                                    the transcript content to the AI</li>
                                                <li data-i18n="customPrompts.tip5">Your output language preference (if
                                                    set) will be applied automatically</li>
                                            </ul>
                                        </div>
                                    </details>
                                </div>
                            </div>

                            <div class="flex justify-end">
                                <button type="submit"
                                    class="inline-flex items-center px-4 py-2 bg-[var(--bg-button)] text-[var(--text-button)] rounded-md hover:bg-[var(--bg-button-hover)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--border-focus)] transition-colors duration-200">
                                    <i class="fas fa-save mr-2"></i> <span data-i18n="buttons.saveSettings">Save
                                        Settings</span>
                                </button>
                            </div>
                        </form>
                    </div>

                    <div id="content-shares" class="hidden tab-content pt-6">
                        <h2 class="text-2xl font-semibold text-[var(--text-primary)] mb-6"
                            data-i18n="accountTabs.sharedTranscripts">My Shared Transcripts</h2>
                        <div id="shares-container" class="space-y-4">
                            <!-- Shares will be loaded here by JavaScript -->
                        </div>
                    </div>

                    <div id="content-speakers" class="hidden tab-content pt-6">
                        <div class="flex-shrink-0">
                            <h2 class="text-2xl font-semibold text-[var(--text-primary)] mb-4"
                                data-i18n="accountTabs.speakersManagement">Speakers Management</h2>
                            <p class="text-[var(--text-secondary)] mb-4" data-i18n="speakersManagement.description">
                                Manage your saved speakers. These are automatically saved when you use speaker names in
                                your recordings.</p>
                        </div>

                        <div class="flex-1 overflow-y-auto min-h-0 pr-2"
                            style="scrollbar-width: thin; scrollbar-color: var(--border-secondary) transparent;">
                            <!-- Loading state -->
                            <div id="speakersTabLoading" class="text-center py-8 hidden">
                                <i class="fas fa-spinner fa-spin text-2xl text-[var(--text-muted)]"></i>
                                <p class="text-[var(--text-muted)] mt-2" data-i18n="speakersManagement.loadingSpeakers">
                                    Loading speakers...</p>
                            </div>

                            <!-- Error state -->
                            <div id="speakersTabError"
                                class="hidden bg-[var(--bg-danger-light)] text-[var(--text-danger-strong)] p-3 rounded-lg mb-4">
                                <i class="fas fa-exclamation-triangle mr-2"></i>
                                <span id="speakersTabErrorMessage" data-i18n="speakersManagement.failedToLoad">Failed to
                                    load speakers</span>
                            </div>

                            <!-- Empty state -->
                            <div id="speakersTabEmpty" class="text-center py-12 hidden">
                                <i class="fas fa-users text-4xl text-[var(--text-light)] mb-4"></i>
                                <p class="text-[var(--text-muted)] text-lg mb-2"
                                    data-i18n="speakersManagement.noSpeakersYet">No speakers saved yet</p>
                                <p class="text-sm text-[var(--text-light)]"
                                    data-i18n="speakersManagement.speakersWillAppear">Speakers will appear here when you
                                    use speaker names in your recordings</p>
                            </div>

                            <!-- Speakers grid with scrollable container -->
                            <div id="speakersTabGrid"
                                class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 pb-4">
                                <!-- Speakers will be populated here -->
                            </div>
                        </div>

                        <!-- Fixed footer with count and actions -->
                        <div
                            class="flex-shrink-0 flex justify-between items-center mt-4 pt-4 border-t border-[var(--border-primary)]">
                            <div class="text-sm text-[var(--text-muted)]">
                                <span id="speakersTabCount">0</span> <span
                                    data-i18n="speakersManagement.totalSpeakers">speakers saved</span>
                            </div>
                            <div class="flex space-x-3">
                                <button id="deleteAllSpeakersTabBtn"
                                    class="px-4 py-2 bg-[var(--bg-danger)] text-[var(--text-button)] rounded-md hover:bg-[var(--bg-danger-hover)] disabled:opacity-50 disabled:cursor-not-allowed"
                                    disabled>
                                    <i class="fas fa-trash mr-2"></i> <span data-i18n="buttons.deleteAll">Delete
                                        All</span>
                                </button>
                            </div>
                        </div>
                    </div>

                    <div id="content-tags" class="hidden tab-content pt-6">
                        <h2 class="text-2xl font-semibold text-[var(--text-primary)] mb-6"
                            data-i18n="accountTabs.tagManagement">Tag Management</h2>

                        <div class="mb-6">
                            <div class="flex justify-between items-center mb-4">
                                <p class="text-[var(--text-secondary)]" data-i18n="tagManagement.description">Organize
                                    your recordings with custom tags. Each tag can have its own summary prompt and
                                    default ASR settings.</p>
                                <button id="createTagBtn"
                                    class="inline-flex items-center px-4 py-2 bg-[var(--bg-button)] text-[var(--text-button)] rounded-md hover:bg-[var(--bg-button-hover)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--border-focus)] transition-colors duration-200">
                                    <i class="fas fa-plus mr-2"></i> <span data-i18n="tagManagement.createTag">Create
                                        Tag</span>
                                </button>
                            </div>

                            <!-- Loading state -->
                            <div id="tagsLoading" class="text-center py-8 hidden">
                                <i class="fas fa-spinner fa-spin text-2xl text-[var(--text-muted)]"></i>
                                <p class="text-[var(--text-muted)] mt-2">Loading tags...</p>
                            </div>

                            <!-- Error state -->
                            <div id="tagsError"
                                class="hidden bg-[var(--bg-danger-light)] text-[var(--text-danger-strong)] p-3 rounded-lg mb-4">
                                <i class="fas fa-exclamation-triangle mr-2"></i>
                                <span id="tagsErrorMessage">Failed to load tags</span>
                            </div>

                            <!-- Empty state -->
                            <div id="tagsEmpty" class="text-center py-12 hidden">
                                <i class="fas fa-tags text-4xl text-[var(--text-light)] mb-4"></i>
                                <p class="text-[var(--text-muted)] text-lg mb-2">尚未创建任何标签</p>
                                <p class="text-sm text-[var(--text-light)]">创建您的第一个标签，以便整理录音文件</p>
                            </div>

                            <!-- Tags grid -->
                            <div id="tagsGrid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
                                <!-- Tags will be populated here -->
                            </div>
                        </div>
                    </div>
                    <div id="content-voiceprint" class="hidden tab-content">
                        <h2 class="text-2xl font-semibold text-[var(--text-primary)] mb-6"
                            style="color: #fff;line-height: 1.5rem;margin: 20px 0 0 0;">声纹管理</h2>
                        <div id="content-voiceprint">

                            <div class="top-bar">
                                <button class="btn btn-primary" style="margin-right: 10px;" onclick="synchronize()">同步至声纹平台</button>
                                <button class="btn btn-primary" onclick="openModal('add')">添加</button>
                            </div>

                            <table id="voiceList">
                                <thead>
                                    <tr>
                                        <th>名称</th>
                                        <th>声纹编码</th>
                                        <!-- <th>创建时间</th> -->
                                        <th>操作</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <!-- 动态渲染数据 -->
                                </tbody>
                            </table>
                        </div>
                        <div id="message"
                            style="z-index:9999;position:fixed;top:20px;right:20px;padding:10px 20px;background:#4caf50;color:white;border-radius:5px;display:none;">
                        </div>
                        <!-- 添加/编辑弹框 -->
                        <div class="modal" id="voiceModal">
                            <div class="modal-content">
                                <div class="modal-header" id="modalTitle">添加说话人</div>
                                <div class="label-tit">
                                    <span style="color: #dc2626;margin-right: 5px;">*</span>
                                    声纹向量
                                </div>
                                <div class="file-box">
                                    <input type="file" id="voiceFile" accept="audio/*">
                                    <button type="button" class="btn-clear" onclick="clearUploadFile()"
                                        style="width: 100px;position: relative;top: -5px;">清空文件</button>
                                </div>

                                <div class="record-box">
                                    <button type="button" onclick="startRecording(this)">🎤 录音</button>
                                    <button type="button" class="btn-clear" onclick="clearRecording()">清空录音</button>
                                </div>

                                <audio id="audioPreview" controls style="display:none;"></audio>
                                <p class="tips">请选择一段清晰的独白语音(2秒以上)，不要包含背景噪音和其他人的声音</p>
                                <div class="label-tit">
                                    <span style="color: #dc2626;margin-right: 5px;">*</span>
                                    名称
                                </div>
                                <input type="text" id="voiceName" placeholder="名称 (必填)" style="background-color: #fff;">
                                <!-- <div class="label-tit">描述</div>
                                <textarea id="voiceDesc" placeholder="描述"
                                    style="background-color: #fff;border-radius: 4px !important;"></textarea> -->
                                <div class="modal-footer">
                                    <button class="btn" onclick="closeModal()">取消</button>
                                    <button class="btn btn-primary" onclick="saveVoice()"
                                        style="color: #fff;">保存</button>
                                </div>
                            </div>
                        </div>

                        <!-- 删除确认弹框 -->
                        <div class="modal" id="confirmDeleteModal">
                            <div class="modal-content">
                                <div class="modal-header" style="color: #000;">确认删除？</div>
                                <div class="modal-footer">
                                    <button class="btn" onclick="closeDeleteModal()" style="border-color: #409eff;
        color: #409eff;">取消</button>
                                    <button class="btn btn-danger" onclick="confirmDelete()"
                                        style="color: #fff;">删除</button>
                                </div>

                            </div>
                        </div>

                    </div>

                    <div id="content-templates" class="hidden tab-content pt-6">
                        <div class="space-y-6">
                            <!-- Templates Header -->
                            <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
                                <div>
                                    <h2 class="text-2xl font-semibold text-[var(--text-primary)]"
                                        data-i18n="transcriptTemplates.title">Transcript Templates</h2>
                                    <p class="text-[var(--text-secondary)]" data-i18n="transcriptTemplates.description">
                                        Customize how transcripts are formatted for download and export.</p>
                                </div>
                                <button id="createTemplateBtn"
                                    class="inline-flex items-center px-4 py-2 bg-[var(--bg-button)] text-[var(--text-button)] rounded-md hover:bg-[var(--bg-button-hover)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--border-focus)] transition-colors duration-200">
                                    <i class="fas fa-plus mr-2"></i>
                                    <span data-i18n="transcriptTemplates.createNew">Create Template</span>
                                </button>
                            </div>

                            <!-- Templates Grid -->
                            <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
                                <!-- Templates List (Left) -->
                                <div class="lg:col-span-1">
                                    <div
                                        class="bg-[var(--bg-secondary)] rounded-lg border border-[var(--border-primary)] p-4">
                                        <h3 class="text-sm font-medium text-[var(--text-secondary)] mb-3"
                                            data-i18n="transcriptTemplates.availableTemplates">Available Templates</h3>
                                        <div id="templatesList" class="space-y-2">
                                            <!-- Templates will be populated here -->
                                        </div>
                                        <button id="createDefaultTemplatesBtn"
                                            class="mt-4 w-full px-3 py-2 text-sm bg-[var(--bg-tertiary)] text-[var(--text-secondary)] rounded-md hover:bg-[var(--bg-accent-light)] transition-colors">
                                            <i class="fas fa-magic mr-2"></i>
                                            <span data-i18n="transcriptTemplates.createDefaults">Create Default
                                                Templates</span>
                                        </button>
                                    </div>
                                </div>

                                <!-- Template Editor (Right) -->
                                <div class="lg:col-span-2">
                                    <div id="templateEditor"
                                        class="bg-[var(--bg-secondary)] rounded-lg border border-[var(--border-primary)] p-6 hidden">
                                        <form id="templateForm" class="space-y-4">
                                            <div>
                                                <label
                                                    class="block text-sm font-medium text-[var(--text-secondary)] mb-1"
                                                    data-i18n="transcriptTemplates.templateName">Template Name</label>
                                                <input type="text" id="templateName"
                                                    class="w-full px-3 py-2 bg-[var(--bg-primary)] text-[var(--text-primary)] border border-[var(--border-primary)] rounded-md focus:outline-none focus:ring-2 focus:ring-[var(--ring-focus)]"
                                                    required>
                                            </div>

                                            <div>
                                                <label
                                                    class="block text-sm font-medium text-[var(--text-secondary)] mb-1"
                                                    data-i18n="transcriptTemplates.description">Description</label>
                                                <input type="text" id="templateDescription"
                                                    class="w-full px-3 py-2 bg-[var(--bg-primary)] text-[var(--text-primary)] border border-[var(--border-primary)] rounded-md focus:outline-none focus:ring-2 focus:ring-[var(--ring-focus)]">
                                            </div>

                                            <div>
                                                <label
                                                    class="block text-sm font-medium text-[var(--text-secondary)] mb-1"
                                                    data-i18n="transcriptTemplates.template">Template</label>
                                                <textarea id="templateContent" rows="6"
                                                    class="w-full px-3 py-2 bg-[var(--bg-primary)] text-[var(--text-primary)] border border-[var(--border-primary)] rounded-md focus:outline-none focus:ring-2 focus:ring-[var(--ring-focus)] font-mono text-sm"
                                                    required></textarea>

                                                <!-- Available Variables -->
                                                <div class="mt-2 p-3 bg-[var(--bg-tertiary)] rounded-md">
                                                    <p class="text-xs font-medium text-[var(--text-secondary)] mb-2"
                                                        data-i18n="transcriptTemplates.availableVars">Available
                                                        Variables:</p>
                                                    <div class="flex flex-wrap gap-2">
                                                        <code
                                                            class="text-xs bg-[var(--bg-primary)] px-2 py-1 rounded">{{index}}</code>
                                                        <code
                                                            class="text-xs bg-[var(--bg-primary)] px-2 py-1 rounded">{{speaker}}</code>
                                                        <code
                                                            class="text-xs bg-[var(--bg-primary)] px-2 py-1 rounded">{{text}}</code>
                                                        <code
                                                            class="text-xs bg-[var(--bg-primary)] px-2 py-1 rounded">{{start_time}}</code>
                                                        <code
                                                            class="text-xs bg-[var(--bg-primary)] px-2 py-1 rounded">{{end_time}}</code>
                                                    </div>
                                                    <p class="text-xs text-[var(--text-muted)] mt-2"
                                                        data-i18n="transcriptTemplates.filters">Filters: |upper for
                                                        uppercase, |srt for subtitle time format</p>
                                                </div>
                                            </div>

                                            <div class="flex items-center">
                                                <input type="checkbox" id="templateIsDefault" class="mr-2">
                                                <label for="templateIsDefault"
                                                    class="text-sm text-[var(--text-secondary)]"
                                                    data-i18n="transcriptTemplates.setDefault">Set as default
                                                    template</label>
                                            </div>

                                            <div class="flex gap-3">
                                                <button type="submit"
                                                    class="px-4 py-2 bg-[var(--bg-button)] text-[var(--text-button)] rounded-md hover:bg-[var(--bg-button-hover)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--border-focus)] transition-colors duration-200">
                                                    <i class="fas fa-save mr-2"></i>
                                                    <span data-i18n="transcriptTemplates.save">保存</span>
                                                </button>
                                                <button type="button" id="cancelTemplateBtn"
                                                    class="px-4 py-2 bg-[var(--bg-tertiary)] text-[var(--text-secondary)] rounded-md hover:bg-[var(--bg-secondary)]">
                                                    <span data-i18n="transcriptTemplates.cancel">取消</span>
                                                </button>
                                                <button type="button" id="deleteTemplateBtn"
                                                    class="px-4 py-2 bg-[var(--bg-danger)] text-white rounded-md hover:bg-[var(--bg-danger-hover)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition-colors duration-200 hidden">
                                                    <i class="fas fa-trash mr-2"></i>
                                                    <span data-i18n="transcriptTemplates.delete">Delete</span>
                                                </button>
                                            </div>
                                        </form>
                                    </div>

                                    <!-- Empty State -->
                                    <div id="templateEmptyState"
                                        class="bg-[var(--bg-secondary)] rounded-lg border border-[var(--border-primary)] p-12 text-center">
                                        <i class="fas fa-file-alt text-4xl text-[var(--text-muted)] mb-4"></i>
                                        <p class="text-[var(--text-muted)]"
                                            data-i18n="transcriptTemplates.selectOrCreate">Select a template to edit or
                                            create a new one</p>
                                    </div>
                                </div>
                            </div>

                            <!-- Documentation Link -->
                            <div class="mt-8 text-center">
                                <a href="https://murtaza-nasir.github.io/speakr/user-guide/transcript-templates/"
                                    target="_blank"
                                    class="text-sm text-[var(--text-muted)] hover:text-[var(--text-secondary)] transition-colors">
                                    <i class="fas fa-question-circle mr-1"></i>
                                    <span data-i18n="transcriptTemplates.viewGuide">View Template Guide</span>
                                </a>
                            </div>
                        </div>
                    </div>

                    <div id="content-about" class="hidden tab-content pt-6">
                        <div class="space-y-8">
                            <!-- Header Section -->
                            <div class="text-center">
                                <div class="flex items-center justify-center mb-4">
                                    <img src="/tool/speakr/static/img/icon-192x192.png" alt="{{ html_title }} Logo"
                                        class="h-16 w-16 mr-4">
                                    <div>
                                        <h2 class="text-3xl font-bold text-[var(--text-primary)]">{{ html_title }}</h2>
                                        <p class="text-[var(--text-secondary)]" data-i18n="aboutPage.tagline">AI-Powered
                                            Audio Transcription & Note-Taking</p>
                                    </div>
                                </div>
                                <div
                                    class="inline-flex items-center px-3 py-1 bg-[var(--bg-accent)] text-[var(--text-accent)] rounded-full text-sm font-medium">
                                    <i class="fas fa-tag mr-2"></i>
                                    Version <span id="system-version" class="ml-1 font-mono">Loading...</span>
                                </div>
                            </div>

                            <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
                                <!-- System Information -->
                                <div
                                    class="bg-[var(--bg-secondary)] rounded-xl p-6 border border-[var(--border-primary)] shadow-sm">
                                    <div class="flex items-center mb-4">
                                        <div class="p-2 bg-[var(--bg-accent)] rounded-lg mr-3">
                                            <i class="fas fa-cogs text-[var(--text-accent)] text-lg"></i>
                                        </div>
                                        <h3 class="text-xl font-semibold text-[var(--text-primary)]"
                                            data-i18n="aboutPage.systemConfiguration">System Configuration</h3>
                                    </div>

                                    <div class="space-y-4">
                                        <div class="border-l-4 border-[var(--border-accent)] pl-4">
                                            <h4 class="font-medium text-[var(--text-primary)] mb-2"
                                                data-i18n="aboutPage.largeLanguageModel">Large Language Model</h4>
                                            <div class="space-y-1 text-sm">
                                                <p class="text-[var(--text-secondary)]">
                                                    <span class="font-medium" data-i18n="aboutPage.model">Model:</span>
                                                    <span id="llm-model"
                                                        class="font-mono text-[var(--text-primary)] bg-[var(--bg-tertiary)] px-2 py-1 rounded ml-1">Loading...</span>
                                                </p>
                                                <p class="text-[var(--text-secondary)]">
                                                    <span class="font-medium"
                                                        data-i18n="aboutPage.endpoint">Endpoint:</span>
                                                    <span id="llm-endpoint"
                                                        class="font-mono text-xs text-[var(--text-muted)] break-all ml-1">Loading...</span>
                                                </p>
                                            </div>
                                        </div>

                                        <div class="border-l-4 border-green-500 pl-4">
                                            <h4 class="font-medium text-[var(--text-primary)] mb-2"
                                                data-i18n="aboutPage.speechRecognition">Speech Recognition</h4>
                                            <div class="space-y-1 text-sm">
                                                <p class="text-[var(--text-secondary)]">
                                                    <span class="font-medium" data-i18n="aboutPage.whisperApi">Whisper
                                                        API:</span>
                                                    <span id="whisper-endpoint"
                                                        class="font-mono text-xs text-[var(--text-muted)] ml-1">Loading...</span>
                                                </p>
                                                <p class="text-[var(--text-secondary)]">
                                                    <span class="font-medium" data-i18n="aboutPage.asrEnabled">ASR
                                                        Enabled:</span>
                                                    <span id="asr-status" class="ml-1">Loading...</span>
                                                </p>
                                                <div id="asr-endpoint-row" style="display: none;">
                                                    <p class="text-[var(--text-secondary)]">
                                                        <span class="font-medium" data-i18n="aboutPage.asrEndpoint">ASR
                                                            Endpoint:</span>
                                                        <span id="asr-endpoint"
                                                            class="font-mono text-xs text-[var(--text-muted)] ml-1">-</span>
                                                    </p>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </div>

                                <!-- Project Information -->
                                <!-- <div class="bg-[var(--bg-secondary)] rounded-xl p-6 border border-[var(--border-primary)] shadow-sm">
                                <div class="flex items-center mb-4">
                                    <div class="p-2 bg-gray-800 rounded-lg mr-3">
                                        <i class="fab fa-github text-white text-lg"></i>
                                    </div>
                                    <h3 class="text-xl font-semibold text-[var(--text-primary)]" data-i18n="aboutPage.projectLinks">Project Links</h3>
                                </div>
                                
                                <div class="space-y-3">
                                    <a href="https://github.com/murtaza-nasir/speakr" target="_blank" rel="noopener noreferrer" 
                                       class="flex items-center p-3 bg-gray-800 hover:bg-gray-700 text-white rounded-lg transition-all duration-200 group transform hover:scale-[1.02]">
                                        <i class="fab fa-github text-xl mr-3"></i>
                                        <div class="flex-1">
                                            <div class="font-medium" data-i18n="aboutPage.githubRepository">GitHub Repository</div>
                                            <div class="text-sm text-gray-300" data-i18n="aboutPage.githubDescription">Source code, issues, and releases</div>
                                        </div>
                                        <i class="fas fa-external-link-alt text-sm opacity-70 group-hover:opacity-100"></i>
                                    </a>
                                    
                                    <a href="https://hub.docker.com/r/learnedmachine/speakr" target="_blank" rel="noopener noreferrer"
                                       class="flex items-center p-3 bg-blue-600 hover:bg-blue-500 text-white rounded-lg transition-all duration-200 group transform hover:scale-[1.02]">
                                        <i class="fab fa-docker text-xl mr-3"></i>
                                        <div class="flex-1">
                                            <div class="font-medium" data-i18n="aboutPage.dockerHub">Docker Hub</div>
                                            <div class="text-sm text-blue-100" data-i18n="aboutPage.dockerDescription">Official Docker images</div>
                                        </div>
                                        <i class="fas fa-external-link-alt text-sm opacity-70 group-hover:opacity-100"></i>
                                    </a>
                                    
                                    <a href="https://murtaza-nasir.github.io/speakr" target="_blank" rel="noopener noreferrer"
                                       class="flex items-center p-3 bg-green-600 hover:bg-green-500 text-white rounded-lg transition-all duration-200 group transform hover:scale-[1.02]">
                                        <i class="fas fa-book text-xl mr-3"></i>
                                        <div class="flex-1">
                                            <div class="font-medium" data-i18n="aboutPage.documentation">Documentation</div>
                                            <div class="text-sm text-green-100" data-i18n="aboutPage.documentationDescription">User guide and tutorials</div>
                                        </div>
                                        <i class="fas fa-external-link-alt text-sm opacity-70 group-hover:opacity-100"></i>
                                    </a>
                                </div>
                                
                                <div class="mt-6 p-3 bg-[var(--bg-tertiary)] rounded-lg border border-[var(--border-secondary)]">
                                    <p class="text-sm text-[var(--text-secondary)] leading-relaxed">
                                        <i class="fas fa-info-circle text-[var(--text-accent)] mr-2"></i>
                                        <span data-i18n="aboutPage.projectDescription">Transform your audio recordings into organized, searchable notes with AI-powered transcription, summarization, and interactive chat features.</span>
                                    </p>
                                </div>
                            </div> -->
                            </div>

                            <!-- Key Features -->
                            <div
                                class="bg-[var(--bg-secondary)] rounded-xl p-6 border border-[var(--border-primary)] shadow-sm">
                                <div class="flex items-center mb-6">
                                    <div class="p-2 bg-purple-600 rounded-lg mr-3">
                                        <i class="fas fa-star text-white text-lg"></i>
                                    </div>
                                    <h3 class="text-xl font-semibold text-[var(--text-primary)]"
                                        data-i18n="aboutPage.keyFeatures">Key Features</h3>
                                </div>

                                <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
                                    <div
                                        class="flex items-start p-4 bg-[var(--bg-tertiary)] rounded-lg border border-[var(--border-secondary)] hover:border-[var(--border-accent)] transition-colors">
                                        <div class="p-2 bg-blue-100 dark:bg-blue-900 rounded-lg mr-3 mt-1">
                                            <i class="fas fa-microphone text-blue-600 dark:text-blue-400"></i>
                                        </div>
                                        <div>
                                            <h4 class="font-medium text-[var(--text-primary)] mb-1"
                                                data-i18n="aboutPage.audioTranscription">Audio Transcription</h4>
                                            <p class="text-sm text-[var(--text-secondary)]"
                                                data-i18n="aboutPage.audioTranscriptionDesc">Whisper API and custom ASR
                                                support with high accuracy</p>
                                        </div>
                                    </div>

                                    <div
                                        class="flex items-start p-4 bg-[var(--bg-tertiary)] rounded-lg border border-[var(--border-secondary)] hover:border-[var(--border-accent)] transition-colors">
                                        <div class="p-2 bg-purple-100 dark:bg-purple-900 rounded-lg mr-3 mt-1">
                                            <i class="fas fa-robot text-purple-600 dark:text-purple-400"></i>
                                        </div>
                                        <div>
                                            <h4 class="font-medium text-[var(--text-primary)] mb-1"
                                                data-i18n="aboutPage.aiSummarization">AI Summarization</h4>
                                            <p class="text-sm text-[var(--text-secondary)]"
                                                data-i18n="aboutPage.aiSummarizationDesc">OpenRouter and Ollama
                                                integration with custom prompts</p>
                                        </div>
                                    </div>

                                    <div
                                        class="flex items-start p-4 bg-[var(--bg-tertiary)] rounded-lg border border-[var(--border-secondary)] hover:border-[var(--border-accent)] transition-colors">
                                        <div class="p-2 bg-green-100 dark:bg-green-900 rounded-lg mr-3 mt-1">
                                            <i class="fas fa-users text-green-600 dark:text-green-400"></i>
                                        </div>
                                        <div>
                                            <h4 class="font-medium text-[var(--text-primary)] mb-1"
                                                data-i18n="aboutPage.speakerDiarization">Speaker Diarization</h4>
                                            <p class="text-sm text-[var(--text-secondary)]"
                                                data-i18n="aboutPage.speakerDiarizationDesc">Identify and label
                                                different speakers automatically</p>
                                        </div>
                                    </div>

                                    <div
                                        class="flex items-start p-4 bg-[var(--bg-tertiary)] rounded-lg border border-[var(--border-secondary)] hover:border-[var(--border-accent)] transition-colors">
                                        <div class="p-2 bg-orange-100 dark:bg-orange-900 rounded-lg mr-3 mt-1">
                                            <i class="fas fa-comments text-orange-600 dark:text-orange-400"></i>
                                        </div>
                                        <div>
                                            <h4 class="font-medium text-[var(--text-primary)] mb-1"
                                                data-i18n="aboutPage.interactiveChat">Interactive Chat</h4>
                                            <p class="text-sm text-[var(--text-secondary)]"
                                                data-i18n="aboutPage.interactiveChatDesc">Chat with your transcriptions
                                                using AI</p>
                                        </div>
                                    </div>

                                    <div
                                        class="flex items-start p-4 bg-[var(--bg-tertiary)] rounded-lg border border-[var(--border-secondary)] hover:border-[var(--border-accent)] transition-colors">
                                        <div class="p-2 bg-indigo-100 dark:bg-indigo-900 rounded-lg mr-3 mt-1">
                                            <i class="fas fa-search text-indigo-600 dark:text-indigo-400"></i>
                                        </div>
                                        <div>
                                            <h4 class="font-medium text-[var(--text-primary)] mb-1"
                                                data-i18n="aboutPage.inquireMode">Inquire Mode</h4>
                                            <p class="text-sm text-[var(--text-secondary)]"
                                                data-i18n="aboutPage.inquireModeDesc">Semantic search across all your
                                                recordings</p>
                                        </div>
                                    </div>

                                    <div
                                        class="flex items-start p-4 bg-[var(--bg-tertiary)] rounded-lg border border-[var(--border-secondary)] hover:border-[var(--border-accent)] transition-colors">
                                        <div class="p-2 bg-teal-100 dark:bg-teal-900 rounded-lg mr-3 mt-1">
                                            <i class="fas fa-share-alt text-teal-600 dark:text-teal-400"></i>
                                        </div>
                                        <div>
                                            <h4 class="font-medium text-[var(--text-primary)] mb-1"
                                                data-i18n="aboutPage.sharingExport">Sharing & Export</h4>
                                            <p class="text-sm text-[var(--text-secondary)]"
                                                data-i18n="aboutPage.sharingExportDesc">Share recordings and export to
                                                various formats</p>
                                        </div>
                                    </div>
                                </div>
                            </div>

                            <!-- Technology Stack -->
                            <div
                                class="bg-[var(--bg-secondary)] rounded-xl p-6 border border-[var(--border-primary)] shadow-sm">
                                <div class="flex items-center mb-4">
                                    <div class="p-2 bg-red-500 rounded-lg mr-3">
                                        <i class="fas fa-code text-white text-lg"></i>
                                    </div>
                                    <h3 class="text-xl font-semibold text-[var(--text-primary)]"
                                        data-i18n="aboutPage.technologyStack">Technology Stack</h3>
                                </div>

                                <div class="grid grid-cols-2 md:grid-cols-4 gap-4">
                                    <div class="text-center p-3 bg-[var(--bg-tertiary)] rounded-lg">
                                        <i class="fab fa-python text-3xl text-blue-500 mb-2"></i>
                                        <p class="text-sm font-medium text-[var(--text-primary)]">Python Flask</p>
                                        <p class="text-xs text-[var(--text-muted)]" data-i18n="aboutPage.backend">
                                            Backend</p>
                                    </div>
                                    <div class="text-center p-3 bg-[var(--bg-tertiary)] rounded-lg">
                                        <i class="fab fa-vuejs text-3xl text-green-500 mb-2"></i>
                                        <p class="text-sm font-medium text-[var(--text-primary)]">Vue.js</p>
                                        <p class="text-xs text-[var(--text-muted)]" data-i18n="aboutPage.frontend">
                                            Frontend</p>
                                    </div>
                                    <div class="text-center p-3 bg-[var(--bg-tertiary)] rounded-lg">
                                        <i class="fas fa-database text-3xl text-purple-500 mb-2"></i>
                                        <p class="text-sm font-medium text-[var(--text-primary)]">SQLite</p>
                                        <p class="text-xs text-[var(--text-muted)]" data-i18n="aboutPage.database">
                                            Database</p>
                                    </div>
                                    <div class="text-center p-3 bg-[var(--bg-tertiary)] rounded-lg">
                                        <i class="fab fa-docker text-3xl text-blue-600 mb-2"></i>
                                        <p class="text-sm font-medium text-[var(--text-primary)]">Docker</p>
                                        <p class="text-xs text-[var(--text-muted)]" data-i18n="aboutPage.deployment">
                                            Deployment</p>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </main>

        <footer class="text-center py-4 mt-8 text-xs text-[var(--text-light)] border-t border-[var(--border-primary)]">
            <span id="footer-text">{{ html_title }} &copy; {{ now.year }}</span>
        </footer>
    </div>

    <!-- Change Password Modal -->
    <div id="changePasswordModal"
        class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
        <div class="bg-[var(--bg-secondary)] p-6 rounded-lg shadow-xl w-full max-w-md">
            <div class="flex justify-between items-center mb-4">
                <h3 class="text-xl font-semibold text-[var(--text-primary)]" data-i18n="account.changePassword">Change
                    Password</h3>
                <button id="closeModalBtn"
                    class="text-[var(--text-light)] hover:text-[var(--text-muted)] text-2xl leading-none">&times;</button>
            </div>
            <form id="changePasswordForm" method="POST" action="/tool/speakr/change_password">
                <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
                <div class="mb-4">
                    <label for="current_password" class="block text-sm font-medium text-[var(--text-secondary)] mb-1"
                        data-i18n="changePasswordModal.currentPassword">Current Password</label>
                    <input type="password" id="current_password" name="current_password" required
                        class="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md focus:outline-none focus:ring-2 focus:ring-[var(--border-focus)] bg-[var(--bg-input)] text-[var(--text-primary)]">
                </div>
                <div class="mb-4">
                    <label for="new_password" class="block text-sm font-medium text-[var(--text-secondary)] mb-1"
                        data-i18n="changePasswordModal.newPassword">New Password</label>
                    <input type="password" id="new_password" name="new_password" required minlength="8"
                        class="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md focus:outline-none focus:ring-2 focus:ring-[var(--border-focus)] bg-[var(--bg-input)] text-[var(--text-primary)]">
                    <p class="text-xs text-[var(--text-muted)] mt-1"
                        data-i18n="changePasswordModal.passwordRequirement">Password must be at least 8 characters long
                    </p>
                </div>
                <div class="mb-6">
                    <label for="confirm_password" class="block text-sm font-medium text-[var(--text-secondary)] mb-1"
                        data-i18n="changePasswordModal.confirmPassword">Confirm New Password</label>
                    <input type="password" id="confirm_password" name="confirm_password" required
                        class="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md focus:outline-none focus:ring-2 focus:ring-[var(--border-focus)] bg-[var(--bg-input)] text-[var(--text-primary)]">
                </div>
                <div class="flex justify-end space-x-3">
                    <button type="button" id="cancelBtn"
                        class="px-4 py-2 bg-[var(--bg-tertiary)] text-[var(--text-secondary)] rounded-md hover:bg-[var(--border-secondary)]">取消</button>
                    <button type="submit"
                        class="px-4 py-2 bg-[var(--bg-button)] text-[var(--text-button)] rounded-md hover:bg-[var(--bg-button-hover)]"
                        data-i18n="account.changePassword">Change Password</button>
                </div>
            </form>
        </div>
    </div>

    <!-- Manage Speakers Modal -->
    <div id="manageSpeakersModal"
        class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
        <div class="bg-[var(--bg-secondary)] p-6 rounded-lg shadow-xl w-full max-w-2xl max-h-[80vh] overflow-hidden">
            <div class="flex justify-between items-center mb-4">
                <h3 class="text-xl font-semibold text-[var(--text-primary)]" data-i18n="account.manageSpeakers">Manage
                    Speakers</h3>
                <button id="closeSpeakersModalBtn"
                    class="text-[var(--text-light)] hover:text-[var(--text-muted)] text-2xl leading-none">&times;</button>
            </div>

            <div class="mb-4">
                <p class="text-sm text-[var(--text-muted)] mb-4">
                    <span data-i18n="manageSpeakersModal.description">Manage your saved speakers. These are
                        automatically saved when you use speaker names in your recordings.</span>
                </p>

                <!-- Loading state -->
                <div id="speakersLoading" class="text-center py-8 hidden">
                    <i class="fas fa-spinner fa-spin text-2xl text-[var(--text-muted)]"></i>
                    <p class="text-[var(--text-muted)] mt-2" data-i18n="manageSpeakersModal.loadingSpeakers">Loading
                        speakers...</p>
                </div>

                <!-- Error state -->
                <div id="speakersError"
                    class="hidden bg-[var(--bg-danger-light)] text-[var(--text-danger-strong)] p-3 rounded-lg mb-4">
                    <i class="fas fa-exclamation-triangle mr-2"></i>
                    <span id="speakersErrorMessage" data-i18n="manageSpeakersModal.failedToLoad">Failed to load
                        speakers</span>
                </div>

                <!-- Empty state -->
                <div id="speakersEmpty" class="text-center py-8 hidden">
                    <i class="fas fa-users text-4xl text-[var(--text-light)] mb-4"></i>
                    <p class="text-[var(--text-muted)]" data-i18n="manageSpeakersModal.noSpeakersYet">No speakers saved
                        yet</p>
                    <p class="text-sm text-[var(--text-light)]" data-i18n="manageSpeakersModal.speakersWillAppear">
                        Speakers will appear here when you use speaker names in your recordings</p>
                </div>

                <!-- Speakers list -->
                <div id="speakersList" class="space-y-2 max-h-96 overflow-y-auto">
                    <!-- Speakers will be populated here -->
                </div>
            </div>

            <div class="flex justify-between items-center pt-4 border-t border-[var(--border-primary)]">
                <div class="text-sm text-[var(--text-muted)]">
                    <span><span id="speakersCount">0</span> <span data-i18n="manageSpeakersModal.speakersSaved">speakers
                            saved</span></span>
                </div>
                <div class="flex space-x-3">
                    <button id="deleteAllSpeakersBtn"
                        class="px-4 py-2 bg-[var(--bg-danger)] text-[var(--text-button)] rounded-md hover:bg-[var(--bg-danger-hover)] disabled:opacity-50 disabled:cursor-not-allowed"
                        disabled>
                        <i class="fas fa-trash mr-2"></i> <span data-i18n="buttons.deleteAll">Delete All</span>
                    </button>
                    <button id="closeSpeakersBtn"
                        class="px-4 py-2 bg-[var(--bg-tertiary)] text-[var(--text-secondary)] rounded-md hover:bg-[var(--border-secondary)]">
                        <span data-i18n="buttons.close">Close</span>
                    </button>
                </div>
            </div>
        </div>
    </div>

    <!-- Delete All Speakers Confirmation Modal -->
    <div id="deleteAllSpeakersModal"
        class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-60 hidden">
        <div class="bg-[var(--bg-secondary)] p-6 rounded-lg shadow-xl w-full max-w-md">
            <div class="flex items-center mb-4">
                <i class="fas fa-exclamation-triangle text-[var(--text-danger)] text-2xl mr-3"></i>
                <h3 class="text-xl font-semibold text-[var(--text-primary)]" data-i18n="buttons.deleteAll">Delete All
                    Speakers</h3>
            </div>
            <p class="text-[var(--text-secondary)] mb-6">
                <span data-i18n="deleteAllSpeakersModal.confirmMessage">Are you sure you want to delete all saved
                    speakers? This action cannot be undone.</span>
            </p>
            <div class="flex justify-end space-x-3">
                <button id="cancelDeleteAllBtn"
                    class="px-4 py-2 bg-[var(--bg-tertiary)] text-[var(--text-secondary)] rounded-md hover:bg-[var(--border-secondary)]">
                    <span data-i18n="buttons.cancel">取消</span>
                </button>
                <button id="confirmDeleteAllBtn"
                    class="px-4 py-2 bg-[var(--bg-danger)] text-[var(--text-button)] rounded-md hover:bg-[var(--bg-danger-hover)]">
                    <i class="fas fa-trash mr-2"></i> Delete All
                </button>
            </div>
        </div>
    </div>

    <!-- Create/Edit Tag Modal -->
    <div id="tagModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
        <div class="bg-[var(--bg-secondary)] p-6 rounded-lg shadow-xl w-full max-w-lg max-h-[90vh] overflow-y-auto">
            <div class="flex justify-between items-center mb-4">
                <h3 id="tagModalTitle" class="text-xl font-semibold text-[var(--text-primary)]"
                    data-i18n="editTagModal.createTitle">Create Tag</h3>
                <button id="closeTagModalBtn"
                    class="text-[var(--text-light)] hover:text-[var(--text-muted)] text-2xl leading-none">&times;</button>
            </div>

            <form id="tagForm" class="space-y-4">
                <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
                <input type="hidden" id="tagId" name="tag_id">

                <div>
                    <label for="tagName" class="block text-sm font-medium text-[var(--text-secondary)] mb-1"
                        data-i18n="editTagModal.tagName">Tag Name *</label>
                    <input type="text" id="tagName" name="name" required maxlength="50"
                        class="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md focus:outline-none focus:ring-2 focus:ring-[var(--border-focus)] bg-[var(--bg-input)] text-[var(--text-primary)]"
                        placeholder="e.g., Meetings, Interviews">
                </div>

                <div>
                    <label for="tagColor" class="block text-sm font-medium text-[var(--text-secondary)] mb-1"
                        data-i18n="editTagModal.color">Color</label>
                    <div class="flex items-center space-x-3">
                        <input type="color" id="tagColor" name="color" value="#3B82F6"
                            class="w-12 h-10 rounded border border-[var(--border-secondary)]">
                        <span class="text-sm text-[var(--text-muted)]" data-i18n="editTagModal.colorDescription">Choose
                            a color for easy identification</span>
                    </div>
                </div>
                <div>
                    <label for="tagScope"
                        class="block text-sm font-medium text-[var(--text-secondary)] mb-1">标签范围{{current_user.is_admin}}</label>
                    <select id="tagScope" name="visibility" required
                        class="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md focus:outline-none focus:ring-2 focus:ring-[var(--border-focus)] bg-[var(--bg-input)] text-[var(--text-primary)]">
                        <option value="global">全局</option>
                        <option value="private">个人</option>
                    </select>
                </div>
                <div>
                    <label for="tagCustomPrompt" class="block text-sm font-medium text-[var(--text-secondary)] mb-1"
                        data-i18n="editTagModal.customPrompt">Custom Summary Prompt</label>
                    <textarea id="tagCustomPrompt" name="custom_prompt" rows="4"
                        class="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md focus:outline-none focus:ring-2 focus:ring-[var(--border-focus)] bg-[var(--bg-input)] text-[var(--text-primary)]"
                        placeholder="Optional: Custom prompt for generating summaries for recordings with this tag"
                        data-i18n-placeholder="editTagModal.customPromptPlaceholder"></textarea>
                    <p class="text-xs text-[var(--text-light)] mt-1" data-i18n="editTagModal.leaveBlankPrompt">Leave
                        blank to use your default summary prompt</p>
                </div>

                {% if use_asr_endpoint %}
                <div class="border-t border-[var(--border-primary)] pt-4">
                    <h4 class="text-sm font-medium text-[var(--text-secondary)] mb-3"
                        data-i18n="editTagModal.asrDefaultSettings">ASR Default Settings</h4>
                    <p class="text-xs text-[var(--text-light)] mb-3" data-i18n="editTagModal.asrSettingsDescription">
                        These settings will be applied by default when using this tag with ASR transcription</p>

                    <div class="space-y-3">
                        <div>
                            <label for="tagLanguage" class="block text-sm font-medium text-[var(--text-muted)] mb-1"
                                data-i18n="editTagModal.defaultLanguage">Default Language</label>
                            <input type="text" id="tagLanguage" name="default_language" maxlength="10"
                                class="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md focus:outline-none focus:ring-2 focus:ring-[var(--border-focus)] bg-[var(--bg-input)] text-[var(--text-primary)]"
                                placeholder="e.g., en, es, zh">
                        </div>

                        <div class="grid grid-cols-2 gap-3">
                            <div>
                                <label for="tagMinSpeakers"
                                    class="block text-sm font-medium text-[var(--text-muted)] mb-1"
                                    data-i18n="editTagModal.minSpeakers">Min Speakers</label>
                                <input type="number" id="tagMinSpeakers" name="default_min_speakers" min="1"
                                    class="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md focus:outline-none focus:ring-2 focus:ring-[var(--border-focus)] bg-[var(--bg-input)] text-[var(--text-primary)]"
                                    </div>

                                <div>
                                    <label for="tagMaxSpeakers"
                                        class="block text-sm font-medium text-[var(--text-muted)] mb-1"
                                        data-i18n="editTagModal.maxSpeakers">Max Speakers</label>
                                    <input type="number" id="tagMaxSpeakers" name="default_max_speakers" min="1"
                                        class="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md focus:outline-none focus:ring-2 focus:ring-[var(--border-focus)] bg-[var(--bg-input)] text-[var(--text-primary)]">
                                </div>
                            </div>
                        </div>
                    </div>
                    {% endif %}

                    <div class="flex justify-end space-x-3 pt-4 border-t border-[var(--border-primary)]">
                        <button type="button" id="cancelTagBtn"
                            class="px-4 py-2 bg-[var(--bg-tertiary)] text-[var(--text-secondary)] rounded-md hover:bg-[var(--border-secondary)]"
                            data-i18n="buttons.cancel">取消</button>
                        <button type="submit" id="saveTagBtn"
                            class="px-4 py-2 bg-[var(--bg-button)] text-[var(--text-button)] rounded-md hover:bg-[var(--bg-button-hover)]">
                            <i class="fas fa-save mr-2"></i> <span data-i18n="buttons.createTag">Save Tag</span>
                        </button>
                    </div>
            </form>
        </div>
    </div>


    <script>
        let voices = []; // 存储声纹数据
        let editIndex = null;
        let deleteIndex = null;
        let mediaRecorder;
        let audioChunks = [];
        let isRecording = false;
        let modetypes = "add"
        let modechooseIndex = 0
        // 打开添加/编辑弹框
        async function openModal(mode, index) {
            document.getElementById('voiceModal').style.display = 'flex';
            document.getElementById('audioPreview').style.display = 'none';
            document.getElementById('voiceFile').value = '';
            document.getElementById('voiceName').value = '';
            // document.getElementById('voiceDesc').value = '';
            modetypes = mode
            modechooseIndex = index
            if (mode === 'add') {
                document.getElementById('modalTitle').innerText = '添加说话人';
                editIndex = null;
            } else if (mode === 'edit') {
                document.getElementById('modalTitle').innerText = '编辑说话人';
                editIndex = index;
                const v = voices[index];
                document.getElementById('voiceName').value = v.name;

                if (v.id) {
                    try {
                        const response = await fetch(`/tool/speakr/api/voiceprints/${v.id}/audio`);
                        if (!response.ok) throw new Error(`获取音频失败：${response.status}`);
                        const blob = await response.blob();
                        const audioURL = URL.createObjectURL(blob);
                        const audio = document.getElementById('audioPreview');
                        audio.src = audioURL;
                        audio.style.display = 'block';
                        v.audio = blob;
                        audioChunks = [blob];  // <-- 新增
console.log("audioChunks 已从远程 Blob 恢复:", audioChunks);
                        console.log('声纹音频已加载并回显:', v.name);
                    } catch (err) {
                        console.error('获取声纹音频失败:', err);
                        alert('无法加载该说话人的音频文件。');
                    }
                }
            }
        }

        // 关闭弹框
        function closeModal() {
            document.getElementById('voiceModal').style.display = 'none';
        }
async function synchronize() {
    
         const response = await fetch(`/tool/speakr/api/voiceprints/sync-local-to-platform`, {
                method: "POST",
            });
            const data = await response.json();
            console.log(data,'data');
            // showMessage(`✅ ${data.message}`, 'success');

            
        }
        // 保存声纹信息
        async function saveVoice() {
            const name = document.getElementById('voiceName').value.trim();
            // const desc 
            // = document.getElementById('voiceDesc').value.trim();
            const fileInput = document.getElementById('voiceFile').files[0];

            if (!name) { alert('名称为必填'); return; }
            if (!fileInput && !audioChunks.length && editIndex === null) {
                alert('请上传或录音声纹');
                return;
            }

            let audioBlob = fileInput ? fileInput : new Blob(audioChunks, { type: 'audio/webm' });
           
            // 测试音频文件
            const reader = new FileReader();
reader.onload = function(e) {
    console.log("audioBlob base64:", e.target.result);
};
reader.readAsDataURL(audioBlob);
console.log("audioBlob type:", audioBlob.type);
console.log("audioBlob size:", audioBlob.size);
console.log("audioBlob instanceof File:", audioBlob instanceof File);
console.log("audioBlob instanceof Blob:", audioBlob instanceof Blob);
console.log("audioBlob:", audioBlob);

            // 使用 FormData 发送音频文件

            const formData = new FormData();
            formData.append("name", name);
            formData.append("voice_data", audioBlob);

            if (modetypes == 'add') {
                try {
                    const response = await fetch("/tool/speakr/api/voiceprints", {
                        method: "POST",
                        body: formData,
                    });
                    const data = await response.json();
                    if (!response.ok) {
                        showMessage(`${data.error}`, 'error');
                        return
                    }
                    closeModal();
                    audioChunks = [];
                    renderList()
                    showMessage(`✅ ${data.message}`, 'success');
                } catch (err) {
                    // console.error("上传出错：", err);
                    // alert("上传失败：" + err.message);
                    showMessage(`${err.message}`, 'error');

                }
            } else {
                try {
                    let v = voices[modechooseIndex]
                    const response = await fetch(`/tool/speakr/api/voiceprints/${v.id}`, {
                        method: "PUT",
                        body: formData,
                    });



                    const data = await response.json();
                    if (!response.ok) {
                        showMessage(`${data.error}`, 'error');
                        return
                    }
                    closeModal();
                    audioChunks = [];
                    renderList()
                    showMessage(`✅ ${data.message}`, 'success');
                } catch (err) {
                    // console.error("上传出错：", err);
                    // alert("上传失败：" + err.message);
                    showMessage(`${err.message}`, 'error');
                }
            }
        }
        function showMessage(msg, type, duration = 3000) {
            const messageDiv = document.getElementById('message');

            if (type === 'error') {
                messageDiv.style.background = '#f44336'; // 红色
            } else if (type === 'warning') {
                messageDiv.style.background = '#ff9800'; // 橙色（可选）
            } else {
                messageDiv.style.background = '#4caf50'; // 默认绿色（成功）
            }
            messageDiv.textContent = msg;
            messageDiv.style.display = 'block';

            setTimeout(() => {
                messageDiv.style.display = 'none';
            }, duration);
        }
        // 渲染列表
        async function renderList() {
            const response = await fetch(`/tool/speakr/api/voiceprints`, {
                method: "GET",
            });
            const data = await response.json();
            // console.log(data,'data');
            voices = data.voiceprints
            const tbody = document.querySelector('#voiceList tbody');
            tbody.innerHTML = '';
            voices.forEach((v, i) => {
                const tr = document.createElement('tr');
                tr.innerHTML = `
            <td>${v.name}</td>
            <td>${v.id}</td>
          
            
            <td>
                <button class="btn-icon" onclick="openModal('edit', ${i})">✏️</button>
                <button class="btn-icon" onclick="openDeleteModal(${i})">🗑️</button>
            </td>
        `;
                tbody.appendChild(tr);
            });
        }

        // 删除逻辑
        function openDeleteModal(index) {
            deleteIndex = index;
            document.getElementById('confirmDeleteModal').style.display = 'flex';
        }
        function closeDeleteModal() {
            document.getElementById('confirmDeleteModal').style.display = 'none';
            deleteIndex = null;
        }
        async function confirmDelete() {
            // if (deleteIndex !== null) voices.splice(deleteIndex, 1);
            console.log(voices[deleteIndex]);
            let v = voices[deleteIndex]
            const response = await fetch(`/tool/speakr/api/voiceprints/${v.id}`, {
                method: "DELETE",
            });
            const data = await response.json();
            if (!response.ok) {
                showMessage(`${data.error}`, 'error');
                return
            }
            console.log(data, 'data');
            renderList();
            closeDeleteModal();
            showMessage(`✅ ${data.message}`, 'success');

        }
        // 清空上传的文件
        function clearUploadFile() {
            const fileInput = document.getElementById('voiceFile');
            fileInput.value = ''; // 清空文件选择
            console.log('✅ 已清空上传的文件');
            // 如果当前显示的音频是上传的文件，也清除
            const audio = document.getElementById('audioPreview');
            if (audio.src && audio.src.startsWith('blob:')) {
                audio.src = '';
                audio.style.display = 'none';
            }
        }

        // 清空录音内容
        function clearRecording() {
            audioChunks = [];
            console.log('✅ 已清空录音内容');
            const audio = document.getElementById('audioPreview');
            audio.src = '';
            audio.style.display = 'none';
        }
        function startRecording(btn) {
            if (isRecording) {
                stopRecording(btn);
                return;
            }

            navigator.mediaDevices.getUserMedia({ audio: true })
                .then(stream => {
                    mediaRecorder = new MediaRecorder(stream);
                    audioChunks = [];
                    mediaRecorder.start();
                    isRecording = true;

                    // 按钮切换为录音中样式
                    btn.textContent = '停止';
                    btn.classList.add('btn-recording');

                    mediaRecorder.ondataavailable = e => audioChunks.push(e.data);

                    mediaRecorder.onstop = () => {
                        isRecording = false;
                        btn.textContent = '🎤 录音';
                        btn.classList.remove('btn-recording');

                        // 生成音频预览
                        const audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
                        const audioURL = URL.createObjectURL(audioBlob);
                        const audio = document.getElementById('audioPreview');
                        audio.src = audioURL;
                        audio.style.display = 'block';

                        // 释放麦克风资源
                        stream.getTracks().forEach(track => track.stop());
                    };
                })
                .catch(err => {
                    alert('无法访问麦克风：' + err.message);
                });
        }

        function stopRecording(btn) {
            if (mediaRecorder && isRecording) {
                mediaRecorder.stop();
            }
        }
        document.addEventListener('DOMContentLoaded', async function () {
            // Initialize i18n
            await initializeI18n();

            // Hide loading overlay after everything is ready
            if (window.AppLoader) {
                AppLoader.waitForReady();
            }

            // Setup scroll indicators for tabs
            const tabsContainer = document.getElementById('tabs-container');
            const leftIndicator = document.getElementById('left-scroll-indicator');
            const rightIndicator = document.getElementById('right-scroll-indicator');

            function updateScrollIndicators() {
                if (tabsContainer && leftIndicator && rightIndicator) {
                    const scrollLeft = tabsContainer.scrollLeft;
                    const scrollWidth = tabsContainer.scrollWidth;
                    const clientWidth = tabsContainer.clientWidth;

                    // Show/hide left indicator
                    if (scrollLeft > 10) {
                        leftIndicator.classList.remove('opacity-0');
                        leftIndicator.classList.add('opacity-100');
                    } else {
                        leftIndicator.classList.add('opacity-0');
                        leftIndicator.classList.remove('opacity-100');
                    }

                    // Show/hide right indicator
                    if (scrollLeft < scrollWidth - clientWidth - 10) {
                        rightIndicator.classList.remove('opacity-0');
                        rightIndicator.classList.add('opacity-100');
                    } else {
                        rightIndicator.classList.add('opacity-0');
                        rightIndicator.classList.remove('opacity-100');
                    }
                }
            }

            if (tabsContainer) {
                tabsContainer.addEventListener('scroll', updateScrollIndicators);
                window.addEventListener('resize', updateScrollIndicators);
                // Initial check - run immediately and after a delay
                updateScrollIndicators();
                setTimeout(updateScrollIndicators, 100);
                setTimeout(updateScrollIndicators, 500);
            }

            const tabAccount = document.getElementById('tab-account');
            const tabPrompts = document.getElementById('tab-prompts');
            const tabShares = document.getElementById('tab-shares');
            const tabTags = document.getElementById('tab-tags');
            const voiceprint = document.getElementById('tab-voiceprint');
            const tabTemplates = document.getElementById('tab-templates');
            const tabAbout = document.getElementById('tab-about');
            const contentAccount = document.getElementById('content-account');
            const contentPrompts = document.getElementById('content-prompts');
            const contentShares = document.getElementById('content-shares');
            const contentSpeakers = document.getElementById('content-speakers');
            const contentTags = document.getElementById('content-tags');
            const contentTemplates = document.getElementById('content-templates');
            const contentVoiceprint = document.getElementById('content-voiceprint');
            const contentAbout = document.getElementById('content-about');
            const sharesContainer = document.getElementById('shares-container');


            // Simplified tab switching
            const tabSpeakers = document.getElementById('tab-speakers');

            const tabs = [
                { tab: tabAccount, content: contentAccount, name: 'account' },
                { tab: tabPrompts, content: contentPrompts, name: 'prompts' },
                { tab: tabShares, content: contentShares, name: 'shares' },
                { tab: tabSpeakers, content: contentSpeakers, name: 'speakers' },
                { tab: tabTags, content: contentTags, name: 'tags' },
                { tab: voiceprint, content: contentVoiceprint, name: 'voiceprint' },
                { tab: tabTemplates, content: contentTemplates, name: 'templates' },
                { tab: tabAbout, content: contentAbout, name: 'about' }
            ];

            function switchToTab(targetName) {
                tabs.forEach(({ tab, content, name }) => {
                    if (name === targetName) {
                        // Active tab
                        tab.classList.add('border-[var(--border-accent)]', 'text-[var(--text-accent)]');
                        tab.classList.remove('border-transparent', 'text-[var(--text-muted)]', 'hover:text-[var(--text-secondary)]', 'hover:border-[var(--border-secondary)]');
                        content.classList.remove('hidden');
                    } else {
                        // Inactive tab
                        tab.classList.add('border-transparent', 'text-[var(--text-muted)]', 'hover:text-[var(--text-secondary)]', 'hover:border-[var(--border-secondary)]');
                        tab.classList.remove('border-[var(--border-accent)]', 'text-[var(--text-accent)]');
                        content.classList.add('hidden');
                    }
                });

                // Load content when switching tabs
                if (targetName === 'speakers') {
                    loadSpeakersTab();
                } else if (targetName === 'shares') {
                    loadShares();
                } else if (targetName === 'tags') {
                    loadTags();
                } else if (targetName === 'templates') {
                    loadTemplates();
                } else if (targetName === 'about') {
                    loadSystemInfo();
                } else if (targetName === 'voiceprint') {
                    loadVoiceprint();
                }
            }

            function showAccountTab() {
                switchToTab('account');
            }

            function showPromptsTab() {
                switchToTab('prompts');
            }

            function showSharesTab() {
                switchToTab('shares');
            }

            function showSpeakersTab() {
                switchToTab('speakers');
            }

            function showTagsTab() {
                switchToTab('tags');
            }

            function showTemplatesTab() {
                switchToTab('templates');
            }
            function showVoiceprint() {
                switchToTab('voiceprint');
            }

            function showAboutTab() {
                switchToTab('about');
            }

            tabAccount.addEventListener('click', (e) => {
                e.preventDefault();
                showAccountTab();
            });

            tabPrompts.addEventListener('click', (e) => {
                e.preventDefault();
                showPromptsTab();
            });

            tabShares.addEventListener('click', (e) => {
                e.preventDefault();
                showSharesTab();
            });

            tabSpeakers.addEventListener('click', (e) => {
                e.preventDefault();
                showSpeakersTab();
            });

            tabTags.addEventListener('click', (e) => {
                e.preventDefault();
                showTagsTab();
            });

            tabTemplates.addEventListener('click', (e) => {
                e.preventDefault();
                showTemplatesTab();
            });

            tabAbout.addEventListener('click', (e) => {
                e.preventDefault();
                showAboutTab();
            });
            voiceprint.addEventListener('click', (e) => {
                e.preventDefault();
                showVoiceprint();
            });

            // Load speakers for the Speakers Management tab
            let speakersTabData = [];
            let speakersTabLoaded = false;

            async function loadSpeakersTab() {
                // Don't reload if already loaded
                if (speakersTabLoaded) return;

                const speakersTabLoading = document.getElementById('speakersTabLoading');
                const speakersTabError = document.getElementById('speakersTabError');
                const speakersTabErrorMessage = document.getElementById('speakersTabErrorMessage');
                const speakersTabEmpty = document.getElementById('speakersTabEmpty');
                const speakersTabGrid = document.getElementById('speakersTabGrid');
                const speakersTabCount = document.getElementById('speakersTabCount');
                const deleteAllSpeakersTabBtn = document.getElementById('deleteAllSpeakersTabBtn');

                // Show loading state
                speakersTabLoading.classList.remove('hidden');
                speakersTabError.classList.add('hidden');
                speakersTabEmpty.classList.add('hidden');
                speakersTabGrid.classList.add('hidden');

                try {
                    const response = await fetch('/tool/speakr/speakers');
                    if (!response.ok) {
                        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
                    }

                    speakersTabData = await response.json();
                    speakersTabLoaded = true;

                    // Hide loading state
                    speakersTabLoading.classList.add('hidden');

                    if (speakersTabData.length === 0) {
                        speakersTabEmpty.classList.remove('hidden');
                        speakersTabGrid.classList.add('hidden');
                        deleteAllSpeakersTabBtn.disabled = true;
                    } else {
                        speakersTabEmpty.classList.add('hidden');
                        speakersTabGrid.classList.remove('hidden');
                        deleteAllSpeakersTabBtn.disabled = false;
                        renderSpeakersTabGrid();
                    }

                    // Update count
                    speakersTabCount.textContent = speakersTabData.length;

                } catch (error) {
                    console.error('Error loading speakers:', error);
                    speakersTabLoading.classList.add('hidden');
                    speakersTabError.classList.remove('hidden');
                    speakersTabEmpty.classList.add('hidden');
                    speakersTabGrid.classList.add('hidden');
                    speakersTabErrorMessage.textContent = error.message;
                    speakersTabCount.textContent = '0';
                }
            }

            function renderSpeakersTabGrid() {
                const speakersTabGrid = document.getElementById('speakersTabGrid');
                speakersTabGrid.innerHTML = '';

                speakersTabData.forEach(speaker => {
                    const createdDate = new Date(speaker.created_at).toLocaleDateString();
                    const lastUsedDate = new Date(speaker.last_used).toLocaleDateString();

                    const speakerCard = document.createElement('div');
                    speakerCard.className = 'bg-[var(--bg-tertiary)] rounded-lg border border-[var(--border-primary)] p-4 hover:border-[var(--border-accent)] transition-colors duration-200';

                    speakerCard.innerHTML = `
                        <div class="flex flex-col h-full">
                            <div class="flex items-start justify-between mb-3">
                                <div class="flex items-center flex-1 min-w-0">
                                    <i class="fas fa-user text-[var(--text-accent)] mr-2 flex-shrink-0"></i>
                                    <h3 class="font-medium text-base text-[var(--text-primary)] truncate">${escapeHtml(speaker.name)}</h3>
                                </div>
                                <button class="delete-speaker-tab-btn ml-2 p-1.5 text-[var(--text-danger)] hover:bg-[var(--bg-danger-light)] rounded-md transition-colors duration-200 flex-shrink-0" 
                                        data-speaker-id="${speaker.id}" 
                                        data-speaker-name="${escapeHtml(speaker.name)}"
                                        data-i18n-title="buttons.deleteSpeaker">
                                    <i class="fas fa-trash text-sm"></i>
                                </button>
                            </div>
                            <div class="space-y-1 text-xs text-[var(--text-muted)]">
                                <p class="flex items-center">
                                    <i class="fas fa-chart-line mr-1.5 text-xs opacity-60"></i>
                                    <span>Used ${speaker.use_count} time${speaker.use_count !== 1 ? 's' : ''}</span>
                                </p>
                                <p class="flex items-center">
                                    <i class="fas fa-clock mr-1.5 text-xs opacity-60"></i>
                                    <span>Last: ${lastUsedDate}</span>
                                </p>
                                <p class="flex items-center">
                                    <i class="fas fa-calendar-plus mr-1.5 text-xs opacity-60"></i>
                                    <span>Added: ${createdDate}</span>
                                </p>
                            </div>
                        </div>
                    `;

                    // Add delete functionality
                    const deleteBtn = speakerCard.querySelector('.delete-speaker-tab-btn');
                    deleteBtn.addEventListener('click', () => deleteSpeakerFromTab(speaker.id, speaker.name));

                    speakersTabGrid.appendChild(speakerCard);
                });
            }

            async function deleteSpeakerFromTab(speakerId, speakerName) {
                if (!confirm(`Are you sure you want to delete "${speakerName}"?`)) {
                    return;
                }

                try {
                    // Get CSRF token
                    const csrfToken = document.querySelector('meta[name=csrf-token]')?.getAttribute('content');

                    const headers = {};
                    if (csrfToken) {
                        headers['X-CSRFToken'] = csrfToken;
                    }

                    const response = await fetch(`/tool/speakr/speakers/${speakerId}`, {
                        method: 'DELETE',
                        headers: headers
                    });

                    if (!response.ok) {
                        const errorData = await response.json();
                        throw new Error(errorData.error || `HTTP ${response.status}: ${response.statusText}`);
                    }

                    // Remove from local array and re-render
                    speakersTabData = speakersTabData.filter(s => s.id !== speakerId);

                    if (speakersTabData.length === 0) {
                        document.getElementById('speakersTabEmpty').classList.remove('hidden');
                        document.getElementById('speakersTabGrid').classList.add('hidden');
                        document.getElementById('deleteAllSpeakersTabBtn').disabled = true;
                    } else {
                        renderSpeakersTabGrid();
                    }

                    document.getElementById('speakersTabCount').textContent = speakersTabData.length;
                    showToast(`Speaker "${speakerName}" deleted successfully`);
                } catch (error) {
                    console.error('Error deleting speaker:', error);
                    showToast(`Failed to delete speaker: ${error.message}`, 'error');
                }
            }

            // Delete all speakers from tab
            document.getElementById('deleteAllSpeakersTabBtn')?.addEventListener('click', async () => {
                if (!confirm('Are you sure you want to delete all speakers? This action cannot be undone.')) {
                    return;
                }

                try {
                    // Get CSRF token
                    const csrfToken = document.querySelector('meta[name=csrf-token]')?.getAttribute('content');

                    const headers = {};
                    if (csrfToken) {
                        headers['X-CSRFToken'] = csrfToken;
                    }

                    // Delete all speakers one by one
                    const deletePromises = speakersTabData.map(speaker =>
                        fetch(`/speakers/${speaker.id}`, {
                            method: 'DELETE',
                            headers: headers
                        })
                    );

                    const results = await Promise.allSettled(deletePromises);

                    // Check for any failures
                    const failures = results.filter(result => result.status === 'rejected');
                    if (failures.length > 0) {
                        console.error('Some speakers failed to delete:', failures);
                        showToast(`${failures.length} speaker(s) failed to delete`, 'error');
                    }

                    // Reset the tab state
                    speakersTabLoaded = false;
                    await loadSpeakersTab();

                    const successCount = results.length - failures.length;
                    if (successCount > 0) {
                        showToast(`${successCount} speaker(s) deleted successfully`);
                    }
                } catch (error) {
                    console.error('Error deleting all speakers:', error);
                    showToast(`Failed to delete speakers: ${error.message}`, 'error');
                }
            });

            async function loadSystemInfo() {
                try {
                    const response = await fetch('/tool/speakr/api/system/info');
                    if (!response.ok) {
                        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
                    }

                    const data = await response.json();

                    // Update version in multiple places
                    document.getElementById('system-version').textContent = data.version;

                    // Update LLM info
                    document.getElementById('llm-endpoint').textContent = data.llm_endpoint;
                    document.getElementById('llm-model').textContent = data.llm_model;

                    // Update Whisper/ASR info
                    document.getElementById('whisper-endpoint').textContent = data.whisper_endpoint;
                    document.getElementById('asr-status').textContent = data.asr_enabled ? 'Yes' : 'No';

                    if (data.asr_enabled && data.asr_endpoint) {
                        document.getElementById('asr-endpoint').textContent = data.asr_endpoint;
                        document.getElementById('asr-endpoint-row').style.display = 'block';
                    }
                } catch (error) {
                    document.getElementById('system-version').textContent = 'Failed to load';
                    document.getElementById('llm-endpoint').textContent = 'Failed to load';
                    document.getElementById('llm-model').textContent = 'Failed to load';
                    document.getElementById('whisper-endpoint').textContent = 'Failed to load';
                    document.getElementById('asr-status').textContent = 'Failed to load';
                }
            }

            async function loadShares() {
                sharesContainer.innerHTML = '<div class="text-center"><i class="fas fa-spinner fa-spin text-2xl"></i></div>';
                try {
                    const response = await fetch('/tool/speakr/api/shares');
                    const shares = await response.json();
                    if (!response.ok) throw new Error(shares.error || 'Failed to load');

                    if (shares.length === 0) {
                        sharesContainer.innerHTML = `<p class="text-center text-[var(--text-muted)]">${t('sharedTranscriptsPage.noSharedTranscripts')}</p>`;
                        return;
                    }

                    sharesContainer.innerHTML = '';
                    shares.forEach(share => {
                        const shareEl = document.createElement('div');
                        shareEl.className = 'bg-[var(--bg-tertiary)] p-4 rounded-lg border border-[var(--border-primary)]';
                        shareEl.innerHTML = `
                            <div class="flex justify-between items-start">
                                <div>
                                    <p class="font-semibold">${escapeHtml(share.recording_title)}</p>
                                    <p class="text-sm text-[var(--text-muted)]">Shared on: ${share.created_at}</p>
                                </div>
                                <button data-share-id="${share.id}" class="delete-share-btn text-red-500 hover:text-red-700 p-1"><i class="fas fa-trash"></i></button>
                            </div>
                            <div class="mt-4 flex items-center gap-4">
                                <label class="flex items-center text-sm">
                                    <input type="checkbox" data-share-id="${share.id}" data-share-prop="share_summary" class="share-checkbox h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" ${share.share_summary ? 'checked' : ''}>
                                    <span class="ml-2">Share Summary</span>
                                </label>
                                <label class="flex items-center text-sm">
                                    <input type="checkbox" data-share-id="${share.id}" data-share-prop="share_notes" class="share-checkbox h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" ${share.share_notes ? 'checked' : ''}>
                                    <span class="ml-2">Share Notes</span>
                                </label>
                            </div>
                            <div class="mt-4">
                                <input value="{{ request.url_root }}share/${share.public_id}" readonly class="w-full px-3 py-2 bg-[var(--bg-input)] border border-[var(--border-secondary)] rounded-lg text-sm">
                            </div>
                        `;
                        sharesContainer.appendChild(shareEl);
                    });

                    document.querySelectorAll('.delete-share-btn').forEach(btn => {
                        btn.addEventListener('click', handleDeleteShare);
                    });
                    document.querySelectorAll('.share-checkbox').forEach(box => {
                        box.addEventListener('change', handleUpdateShare);
                    });

                } catch (error) {
                    sharesContainer.innerHTML = `<p class="text-center text-red-500">${t('errors.loadingShares')}: ${error.message}</p>`;
                }
            }

            async function handleDeleteShare(event) {
                const shareId = event.currentTarget.dataset.shareId;
                if (!confirm('Are you sure you want to delete this share? This will revoke access to the public link.')) return;

                try {
                    // Get CSRF token
                    const csrfToken = document.querySelector('meta[name=csrf-token]')?.getAttribute('content');

                    const headers = {};
                    if (csrfToken) {
                        headers['X-CSRFToken'] = csrfToken;
                    }

                    const response = await fetch(`/tool/speakr/api/share/${shareId}`, {
                        method: 'DELETE',
                        headers: headers
                    });
                    if (!response.ok) throw new Error('Failed to delete');
                    loadShares();
                } catch (error) {
                    alert('Error deleting share.');
                }
            }

            async function handleUpdateShare(event) {
                const shareId = event.currentTarget.dataset.shareId;
                const prop = event.currentTarget.dataset.shareProp;
                const value = event.currentTarget.checked;

                try {
                    // Get CSRF token
                    const csrfToken = document.querySelector('meta[name=csrf-token]')?.getAttribute('content');

                    const headers = { 'Content-Type': 'application/json' };
                    if (csrfToken) {
                        headers['X-CSRFToken'] = csrfToken;
                    }

                    const response = await fetch(`/tool/speakr/api/share/${shareId}`, {
                        method: 'PUT',
                        headers: headers,
                        body: JSON.stringify({ [prop]: value })
                    });
                    if (!response.ok) throw new Error('Failed to update');
                } catch (error) {
                    alert('Error updating share.');
                    event.currentTarget.checked = !value; // Revert on failure
                }
            }

            function escapeHtml(text) {
                const div = document.createElement('div');
                div.textContent = text;
                return div.innerHTML;
            }

            // Update footer with version
            async function updateFooter() {
                try {
                    const response = await fetch('/tool/speakr/api/system/info');
                    if (response.ok) {
                        const data = await response.json();
                        const footerText = document.getElementById('footer-text');
                        if (footerText && data.version) {
                            footerText.textContent = `{{ html_title }} ${data.version} © {{ now.year }}`;
                        }
                    }
                } catch (error) {
                    console.log('Could not fetch version for footer');
                }
            }

            // Update footer on page load
            updateFooter();

            // Dark mode toggle functionality
            const darkModeToggle = document.getElementById('darkModeToggle');
            const darkModeIcon = document.getElementById('darkModeIcon');

            // Initialize dark mode based on localStorage or system preference
            function initializeDarkMode() {
                const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
                const savedMode = localStorage.getItem('darkMode');

                if (savedMode === 'true' || (savedMode === null && prefersDark)) {
                    document.documentElement.classList.add('dark');
                    darkModeIcon.classList.remove('fa-moon');
                    darkModeIcon.classList.add('fa-sun');
                } else {
                    document.documentElement.classList.remove('dark');
                    darkModeIcon.classList.remove('fa-sun');
                    darkModeIcon.classList.add('fa-moon');
                }
            }

            // Toggle dark mode
            darkModeToggle.addEventListener('click', () => {
                const isDarkMode = document.documentElement.classList.toggle('dark');
                localStorage.setItem('darkMode', isDarkMode);

                if (isDarkMode) {
                    darkModeIcon.classList.remove('fa-moon');
                    darkModeIcon.classList.add('fa-sun');
                } else {
                    darkModeIcon.classList.remove('fa-sun');
                    darkModeIcon.classList.add('fa-moon');
                }
            });

            // User dropdown functionality
            const userDropdownButton = document.getElementById('userDropdownButton');
            const userDropdownMenu = document.getElementById('userDropdownMenu');

            userDropdownButton.addEventListener('click', () => {
                userDropdownMenu.classList.toggle('hidden');
            });

            // Close dropdown when clicking outside
            document.addEventListener('click', (event) => {
                if (!userDropdownButton.contains(event.target) && !userDropdownMenu.contains(event.target)) {
                    userDropdownMenu.classList.add('hidden');
                }
            });

            // Initialize dark mode on page load
            initializeDarkMode();

            // Change Password Modal functionality
            const changePasswordBtn = document.getElementById('changePasswordBtn');
            const changePasswordModal = document.getElementById('changePasswordModal');
            const closeModalBtn = document.getElementById('closeModalBtn');
            const cancelBtn = document.getElementById('cancelBtn');
            const changePasswordForm = document.getElementById('changePasswordForm');
            const newPasswordInput = document.getElementById('new_password');
            const confirmPasswordInput = document.getElementById('confirm_password');

            // Open modal
            changePasswordBtn.addEventListener('click', () => {
                changePasswordModal.classList.remove('hidden');
                // Reset form
                changePasswordForm.reset();
            });

            // Close modal functions
            function closeModal() {
                changePasswordModal.classList.add('hidden');
            }

            closeModalBtn.addEventListener('click', closeModal);
            cancelBtn.addEventListener('click', closeModal);

            // Close modal when clicking outside
            changePasswordModal.addEventListener('click', (event) => {
                if (event.target === changePasswordModal) {
                    closeModal();
                }
            });

            // Form validation
            changePasswordForm.addEventListener('submit', (event) => {
                if (newPasswordInput.value !== confirmPasswordInput.value) {
                    event.preventDefault();
                    alert('New password and confirmation do not match.');
                }
            });

            // Keep the modal functionality for backward compatibility if button still exists
            const manageSpeakersBtn = document.getElementById('manageSpeakersBtn');
            const manageSpeakersModal = document.getElementById('manageSpeakersModal');
            const closeSpeakersModalBtn = document.getElementById('closeSpeakersModalBtn');
            const closeSpeakersBtn = document.getElementById('closeSpeakersBtn');
            const deleteAllSpeakersBtn = document.getElementById('deleteAllSpeakersBtn');
            const deleteAllSpeakersModal = document.getElementById('deleteAllSpeakersModal');
            const cancelDeleteAllBtn = document.getElementById('cancelDeleteAllBtn');
            const confirmDeleteAllBtn = document.getElementById('confirmDeleteAllBtn');

            const speakersLoading = document.getElementById('speakersLoading');
            const speakersError = document.getElementById('speakersError');
            const speakersErrorMessage = document.getElementById('speakersErrorMessage');
            const speakersEmpty = document.getElementById('speakersEmpty');
            const speakersList = document.getElementById('speakersList');
            const speakersCount = document.getElementById('speakersCount');

            let speakers = [];

            // Open speakers modal only if button exists
            if (manageSpeakersBtn) {
                manageSpeakersBtn.addEventListener('click', () => {
                    manageSpeakersModal.classList.remove('hidden');
                    loadSpeakers();
                });
            }

            // Close speakers modal functions
            function closeSpeakersModal() {
                manageSpeakersModal.classList.add('hidden');
            }

            closeSpeakersModalBtn.addEventListener('click', closeSpeakersModal);
            closeSpeakersBtn.addEventListener('click', closeSpeakersModal);

            // Close modal when clicking outside
            manageSpeakersModal.addEventListener('click', (event) => {
                if (event.target === manageSpeakersModal) {
                    closeSpeakersModal();
                }
            });

            // Load speakers from API
            async function loadSpeakers() {
                showLoadingState();

                try {
                    const response = await fetch('/tool/speakr/speakers');
                    if (!response.ok) {
                        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
                    }

                    speakers = await response.json();
                    displaySpeakers();
                } catch (error) {
                    console.error('Error loading speakers:', error);
                    showErrorState(error.message);
                }
            }

            // Show loading state
            function showLoadingState() {
                speakersLoading.classList.remove('hidden');
                speakersError.classList.add('hidden');
                speakersEmpty.classList.add('hidden');
                speakersList.classList.add('hidden');
            }

            // Show error state
            function showErrorState(message) {
                speakersLoading.classList.add('hidden');
                speakersError.classList.remove('hidden');
                speakersEmpty.classList.add('hidden');
                speakersList.classList.add('hidden');
                speakersErrorMessage.textContent = message;
                updateSpeakersCount(0);
            }

            // Display speakers
            function displaySpeakers() {
                speakersLoading.classList.add('hidden');
                speakersError.classList.add('hidden');

                if (speakers.length === 0) {
                    speakersEmpty.classList.remove('hidden');
                    speakersList.classList.add('hidden');
                    deleteAllSpeakersBtn.disabled = true;
                } else {
                    speakersEmpty.classList.add('hidden');
                    speakersList.classList.remove('hidden');
                    deleteAllSpeakersBtn.disabled = false;
                    renderSpeakersList();
                }

                updateSpeakersCount(speakers.length);
            }

            // Render speakers list
            function renderSpeakersList() {
                speakersList.innerHTML = '';

                speakers.forEach(speaker => {
                    const speakerItem = createSpeakerItem(speaker);
                    speakersList.appendChild(speakerItem);
                });
            }

            // Create speaker item element
            function createSpeakerItem(speaker) {
                const div = document.createElement('div');
                div.className = 'flex items-center justify-between p-3 bg-[var(--bg-tertiary)] rounded-lg border border-[var(--border-primary)] hover:bg-[var(--bg-accent)] transition-colors duration-200';

                const createdDate = new Date(speaker.created_at).toLocaleDateString();
                const lastUsedDate = new Date(speaker.last_used).toLocaleDateString();

                div.innerHTML = `
                <div class="flex-1">
                    <div class="flex items-center">
                        <i class="fas fa-user text-[var(--text-muted)] mr-2"></i>
                        <span class="font-medium text-[var(--text-primary)]">${escapeHtml(speaker.name)}</span>
                    </div>
                    <div class="text-xs text-[var(--text-muted)] mt-1">
                        Used ${speaker.use_count} time${speaker.use_count !== 1 ? 's' : ''} • 
                        Last used: ${lastUsedDate} • 
                        Created: ${createdDate}
                    </div>
                </div>
                <button class="delete-speaker-btn ml-3 p-2 text-[var(--text-danger)] hover:bg-[var(--bg-danger-light)] rounded-md transition-colors duration-200" 
                        data-speaker-id="${speaker.id}" 
                        data-i18n-title="buttons.deleteSpeaker">
                    <i class="fas fa-trash text-sm"></i>
                </button>
            `;

                // Add delete functionality
                const deleteBtn = div.querySelector('.delete-speaker-btn');
                deleteBtn.addEventListener('click', () => deleteSpeaker(speaker.id, speaker.name));

                return div;
            }

            // Delete individual speaker
            async function deleteSpeaker(speakerId, speakerName) {
                if (!confirm(`Are you sure you want to delete "${speakerName}"?`)) {
                    return;
                }

                try {
                    // Get CSRF token
                    const csrfToken = document.querySelector('meta[name=csrf-token]')?.getAttribute('content');

                    const headers = {};
                    if (csrfToken) {
                        headers['X-CSRFToken'] = csrfToken;
                    }

                    const response = await fetch(`/tool/speakr/speakers/${speakerId}`, {
                        method: 'DELETE',
                        headers: headers
                    });

                    if (!response.ok) {
                        const errorData = await response.json();
                        throw new Error(errorData.error || `HTTP ${response.status}: ${response.statusText}`);
                    }

                    // Remove from local array
                    speakers = speakers.filter(s => s.id !== speakerId);
                    displaySpeakers();
                    showToast(`Speaker "${speakerName}" deleted successfully`);
                } catch (error) {
                    console.error('Error deleting speaker:', error);
                    showToast(`Failed to delete speaker: ${error.message}`, 'error');
                }
            }

            // Delete all speakers
            deleteAllSpeakersBtn.addEventListener('click', () => {
                deleteAllSpeakersModal.classList.remove('hidden');
            });

            // Cancel delete all
            cancelDeleteAllBtn.addEventListener('click', () => {
                deleteAllSpeakersModal.classList.add('hidden');
            });

            // Close delete all modal when clicking outside
            deleteAllSpeakersModal.addEventListener('click', (event) => {
                if (event.target === deleteAllSpeakersModal) {
                    deleteAllSpeakersModal.classList.add('hidden');
                }
            });

            // Confirm delete all speakers
            confirmDeleteAllBtn.addEventListener('click', async () => {
                deleteAllSpeakersModal.classList.add('hidden');

                try {
                    // Get CSRF token
                    const csrfToken = document.querySelector('meta[name=csrf-token]')?.getAttribute('content');

                    const headers = {};
                    if (csrfToken) {
                        headers['X-CSRFToken'] = csrfToken;
                    }

                    // Delete all speakers one by one
                    const deletePromises = speakers.map(speaker =>
                        fetch(`/speakers/${speaker.id}`, {
                            method: 'DELETE',
                            headers: headers
                        })
                    );

                    const results = await Promise.allSettled(deletePromises);

                    // Check for any failures
                    const failures = results.filter(result => result.status === 'rejected');
                    if (failures.length > 0) {
                        console.error('Some speakers failed to delete:', failures);
                        showToast(`${failures.length} speaker(s) failed to delete`, 'error');
                    }

                    // Reload speakers list
                    await loadSpeakers();
                    showToast(`${speakers.length === 0 ? 'All speakers' : (results.length - failures.length) + ' speakers'} deleted successfully`);
                } catch (error) {
                    console.error('Error deleting all speakers:', error);
                    showToast(`Failed to delete speakers: ${error.message}`, 'error');
                }
            });

            // Update speakers count
            function updateSpeakersCount(count) {
                speakersCount.textContent = count;
            }

            // Utility function to escape HTML
            function escapeHtml(text) {
                const div = document.createElement('div');
                div.textContent = text;
                return div.innerHTML;
            }

            // Toast notification function
            function showToast(message, type = 'success') {
                // Create toast element
                const toast = document.createElement('div');
                toast.className = `fixed top-4 right-4 z-50 px-4 py-2 rounded-lg shadow-lg transition-all duration-300 transform translate-x-full ${type === 'error'
                    ? 'bg-[var(--bg-danger)] text-[var(--text-button)]'
                    : 'bg-[var(--bg-success-light)] text-[var(--text-success-strong)]'
                    }`;
                toast.innerHTML = `
                <div class="flex items-center">
                    <i class="fas ${type === 'error' ? 'fa-exclamation-circle' : 'fa-check-circle'} mr-2"></i>
                    <span>${escapeHtml(message)}</span>
                </div>
            `;

                document.body.appendChild(toast);

                // Animate in
                setTimeout(() => {
                    toast.classList.remove('translate-x-full');
                }, 10);

                // Animate out and remove
                setTimeout(() => {
                    toast.classList.add('translate-x-full');
                    setTimeout(() => {
                        document.body.removeChild(toast);
                    }, 300);
                }, 3000);
            }

            // ===== TAG MANAGEMENT FUNCTIONALITY =====

            // Tag management elements
            const createTagBtn = document.getElementById('createTagBtn');
            const tagModal = document.getElementById('tagModal');
            const closeTagModalBtn = document.getElementById('closeTagModalBtn');
            const cancelTagBtn = document.getElementById('cancelTagBtn');
            const tagForm = document.getElementById('tagForm');
            const tagModalTitle = document.getElementById('tagModalTitle');
            const saveTagBtn = document.getElementById('saveTagBtn');

            const tagsLoading = document.getElementById('tagsLoading');
            const tagsError = document.getElementById('tagsError');
            const tagsErrorMessage = document.getElementById('tagsErrorMessage');
            const tagsEmpty = document.getElementById('tagsEmpty');
            const tagsGrid = document.getElementById('tagsGrid');

            let tags = [];
            let isEditingTag = false;

            // Load tags from API
            async function loadTags() {
                showTagsLoadingState();

                try {
                    const response = await fetch('/tool/speakr/api/tags');
                    if (!response.ok) {
                        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
                    }

                    tags = await response.json();
                    displayTags();
                } catch (error) {
                    console.error('Error loading tags:', error);
                    showTagsErrorState(error.message);
                }
            }


            async function loadVoiceprint() {
                showTagsLoadingState();
                renderList()


                // try {
                //     const response = await fetch('/tool/speakr/api/tags');
                //     if (!response.ok) {
                //         throw new Error(`HTTP ${response.status}: ${response.statusText}`);
                //     }

                //     tags = await response.json();
                //     displayTags();
                // } catch (error) {
                //     console.error('Error loading tags:', error);
                //     showTagsErrorState(error.message);
                // }
            }

            // Show loading state
            function showTagsLoadingState() {
                tagsLoading.classList.remove('hidden');
                tagsError.classList.add('hidden');
                tagsEmpty.classList.add('hidden');
                tagsGrid.classList.add('hidden');
            }

            // Show error state
            function showTagsErrorState(message) {
                tagsLoading.classList.add('hidden');
                tagsError.classList.remove('hidden');
                tagsEmpty.classList.add('hidden');
                tagsGrid.classList.add('hidden');
                tagsErrorMessage.textContent = message;
            }

            // Display tags
            function displayTags() {
                tagsLoading.classList.add('hidden');
                tagsError.classList.add('hidden');

                if (tags.length === 0) {
                    tagsEmpty.classList.remove('hidden');
                    tagsGrid.classList.add('hidden');
                } else {
                    tagsEmpty.classList.add('hidden');
                    tagsGrid.classList.remove('hidden');
                    renderTagsGrid();
                }
            }

            // Render tags grid
            function renderTagsGrid() {
                tagsGrid.innerHTML = '';

                tags.forEach(tag => {
                    const tagCard = createTagCard(tag);
                    tagsGrid.appendChild(tagCard);
                });
            }
            let frontendCurrentUser = {
                isAdmin: {{ current_user.is_admin| tojson
        }}
    }
            // Create tag card element
            function createTagCard(tag) {
                const div = document.createElement('div');
                div.className = 'bg-[var(--bg-tertiary)] p-4 rounded-lg border border-[var(--border-primary)] hover:shadow-md transition-shadow duration-200';
                console.log(frontendCurrentUser, 'current_user', tag.visibility);

                div.innerHTML = `
                <div class="flex items-start justify-between mb-3">
                    <div class="flex items-center">
                        <div class="w-4 h-4 rounded-full mr-3" style="background-color: ${escapeHtml(tag.color)}"></div>
                        <h3 class="font-semibold text-[var(--text-primary)]">${escapeHtml(tag.name)}${tag.visibility == "global" ? "(全局)" : "(个人)"}</h3>
                    </div>
                   ${(frontendCurrentUser.isAdmin || tag.visibility != "global") ? `
            <div class="flex space-x-1">
                <button class="edit-tag-btn p-1 text-[var(--text-muted)] hover:text-[var(--text-accent)] rounded" 
                        data-tag-id="${tag.id}" data-i18n-title="buttons.editTag">
                    <i class="fas fa-edit text-sm"></i>
                </button>
                <button class="delete-tag-btn p-1 text-[var(--text-muted)] hover:text-[var(--text-danger)] rounded" 
                        data-tag-id="${tag.id}" data-i18n-title="buttons.deleteTag">
                    <i class="fas fa-trash text-sm"></i>
                </button>
            </div>
        ` : ''}
                </div>
                
                <div class="space-y-2 text-sm text-[var(--text-muted)]">
                    ${tag.custom_prompt ? `
                        <div>
                            <span class="font-medium" data-i18n="tagManagement.customPrompt">Custom Prompt:</span>
                            <span class="text-xs">${escapeHtml(tag.custom_prompt.substring(0, 60))}${tag.custom_prompt.length > 60 ? '...' : ''}</span>
                        </div>
                    ` : ''}
                    
                    ${tag.default_language || tag.default_min_speakers || tag.default_max_speakers ? `
                        <div class="pt-2 border-t border-[var(--border-secondary)]">
                            <span class="font-medium text-xs" data-i18n="tagManagement.asrDefaults">ASR Defaults:</span>
                            <div class="flex flex-wrap gap-2 mt-1">
                                ${tag.default_language ? `<span class="inline-flex items-center px-2 py-1 rounded-full text-xs bg-[var(--bg-accent)] text-[var(--text-accent)]">Lang: ${escapeHtml(tag.default_language)}</span>` : ''}
                                ${tag.default_min_speakers ? `<span class="inline-flex items-center px-2 py-1 rounded-full text-xs bg-[var(--bg-accent)] text-[var(--text-accent)]">Min: ${tag.default_min_speakers}</span>` : ''}
                                ${tag.default_max_speakers ? `<span class="inline-flex items-center px-2 py-1 rounded-full text-xs bg-[var(--bg-accent)] text-[var(--text-accent)]">Max: ${tag.default_max_speakers}</span>` : ''}
                            </div>
                        </div>
                    ` : ''}
                </div>
            `;

                // Add event listeners
                const editBtn = div.querySelector('.edit-tag-btn');
                const deleteBtn = div.querySelector('.delete-tag-btn');
                if (frontendCurrentUser.isAdmin || tag.visibility != "global") {
                    editBtn.addEventListener('click', () => editTag(tag));
                    deleteBtn.addEventListener('click', () => deleteTag(tag.id, tag.name));
                }



                return div;
            }

        // Create tag modal functionality
        createTagBtn.addEventListener('click', () => {
                openTagModal();
            });

        // Close tag modal functions
        function closeTagModal() {
            tagModal.classList.add('hidden');
            tagForm.reset();
            isEditingTag = false;
            document.getElementById('tagId').value = '';
        }

        closeTagModalBtn.addEventListener('click', closeTagModal);
        cancelTagBtn.addEventListener('click', closeTagModal);

        // Close modal when clicking outside
        tagModal.addEventListener('click', (event) => {
            if (event.target === tagModal) {
                closeTagModal();
            }
        });

        // Open tag modal for create
        function openTagModal(tag = null) {
            if (tag) {
                // Edit mode
                isEditingTag = true;
                tagModalTitle.textContent = 'Edit Tag';
                saveTagBtn.innerHTML = '<i class="fas fa-save mr-2"></i> Update Tag';

                // Populate form
                document.getElementById('tagId').value = tag.id;
                document.getElementById('tagName').value = tag.name;
                document.getElementById('tagColor').value = tag.color;
                document.getElementById('tagCustomPrompt').value = tag.custom_prompt || '';
                document.getElementById('tagScope').value = tag.visibility || '';

                if (document.getElementById('tagLanguage')) {
                    document.getElementById('tagLanguage').value = tag.default_language || '';
                }
                if (document.getElementById('tagMinSpeakers')) {
                    document.getElementById('tagMinSpeakers').value = tag.default_min_speakers || '';
                }
                if (document.getElementById('tagMaxSpeakers')) {
                    document.getElementById('tagMaxSpeakers').value = tag.default_max_speakers || '';
                }
            } else {
                // Create mode
                isEditingTag = false;
                tagModalTitle.textContent = 'Create Tag';
                saveTagBtn.innerHTML = '<i class="fas fa-save mr-2"></i> Save Tag';
                tagForm.reset();
                document.getElementById('tagColor').value = '#3B82F6';
            }

            tagModal.classList.remove('hidden');
        }

        // Edit tag
        function editTag(tag) {
            openTagModal(tag);
        }

        // Delete tag
        async function deleteTag(tagId, tagName) {
            if (!confirm(`Are you sure you want to delete "${tagName}"?`)) {
                return;
            }

            try {
                const csrfToken = document.querySelector('meta[name=csrf-token]')?.getAttribute('content');

                const headers = {};
                if (csrfToken) {
                    headers['X-CSRFToken'] = csrfToken;
                }

                const response = await fetch(`/tool/speakr/api/tags/${tagId}`, {
                    method: 'DELETE',
                    headers: headers
                });

                if (!response.ok) {
                    const errorData = await response.json();
                    throw new Error(errorData.error || `HTTP ${response.status}: ${response.statusText}`);
                }

                // Remove from local array
                tags = tags.filter(t => t.id !== tagId);
                displayTags();
                showToast(`Tag "${tagName}" deleted successfully`);
            } catch (error) {
                console.error('Error deleting tag:', error);
                showToast(`Failed to delete tag: ${error.message}`, 'error');
            }
        }

        // Save tag form submission
        tagForm.addEventListener('submit', async (e) => {
            e.preventDefault();

            const formData = new FormData(tagForm);
            const tagData = {
                name: formData.get('name'),
                color: formData.get('color'),
                custom_prompt: formData.get('custom_prompt') || null,
                default_language: formData.get('default_language') || null,
                visibility: formData.get('visibility') || null,

                default_min_speakers: formData.get('default_min_speakers') ? parseInt(formData.get('default_min_speakers')) : null,
                default_max_speakers: formData.get('default_max_speakers') ? parseInt(formData.get('default_max_speakers')) : null
            };

            try {
                const csrfToken = document.querySelector('meta[name=csrf-token]')?.getAttribute('content');

                const headers = { 'Content-Type': 'application/json' };
                if (csrfToken) {
                    headers['X-CSRFToken'] = csrfToken;
                }

                let url = '/tool/speakr/api/tags';
                let method = 'POST';

                if (isEditingTag) {
                    url += `/${formData.get('tag_id')}`;
                    method = 'PUT';
                }

                const response = await fetch(url, {
                    method: method,
                    headers: headers,
                    body: JSON.stringify(tagData)
                });

                if (!response.ok) {
                    const errorData = await response.json();
                    throw new Error(errorData.error || `HTTP ${response.status}: ${response.statusText}`);
                }

                const savedTag = await response.json();

                if (isEditingTag) {
                    // Update existing tag in local array
                    const index = tags.findIndex(t => t.id === savedTag.id);
                    if (index !== -1) {
                        tags[index] = savedTag;
                    }
                    showToast(`Tag "${savedTag.name}" updated successfully`);
                } else {
                    // Add new tag to local array
                    tags.push(savedTag);
                    showToast(`Tag "${savedTag.name}" created successfully`);
                }

                displayTags();
                closeTagModal();
            } catch (error) {
                console.error('Error saving tag:', error);
                showToast(`Failed to save tag: ${error.message}`, 'error');
            }
        });

        // AJAX form submission for Account Information
        const accountInfoForm = document.getElementById('accountInfoForm');
        const canManageSystemConfigs = {{ current_user.is_admin | tojson }};
        let currentConfigScene = String(localStorage.getItem('selectedScene') || 'cg').trim().toLowerCase() === 'yl' ? 'yl' : 'cg';
        const accountSceneCgButton = document.getElementById('accountSceneCg');
        const accountSceneYlButton = document.getElementById('accountSceneYl');
        let textareacot = ''
        const textarea = document.querySelector('textarea.hot-textarea');
        if (textarea) {
            textarea.addEventListener('input', function (e) {
                const currentValue = e.target.value;
                textareacot = currentValue
                console.log('textarea值已更新：', currentValue);
            });
        }
        async function updataBaseHot(params) {
            if (!textarea || !textareacot.trim()) {
                return;
            }
            const response = await fetch(`/tool/speakr/api/hotwords`, {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    hotwords: textareacot,
                    scene: currentConfigScene,
                }),
            });
            const data = await response.json();
            if (!response.ok)
                throw new Error(data.error || "Failed to create share link");
            //   console.log(data.summary, "接收到回参");

        }
        async function getBaseHot(params) {
            const response = await fetch(
                `/tool/speakr/api/hotwords?scene=${currentConfigScene}`,
                {
                    method: "GET",
                }
            );
            const data = await response.json();
            if (response.ok) {
                console.log(data, 'data');
                updateTextareaValue(data.text_format)
            }

        }

        let textareahandlecot = ''
        const textareahandle = document.querySelector('textarea.handle-textarea');
        if (textareahandle) {
            textareahandle.addEventListener('input', function (e) {
                const currentValue = e.target.value;
                textareahandlecot = currentValue
            });
        }

        function normalizeAccountScene(scene) {
            return String(scene || 'cg').trim().toLowerCase() === 'yl' ? 'yl' : 'cg';
        }

        function getStandardWordMappingsConfigKey() {
            return currentConfigScene === 'yl' ? 'standard_word_mappings_yl' : 'standard_word_mappings';
        }

        function refreshAccountSceneButtons() {
            if (accountSceneCgButton) {
                accountSceneCgButton.classList.toggle('bg-[var(--bg-button)]', currentConfigScene === 'cg');
                accountSceneCgButton.classList.toggle('text-[var(--text-button)]', currentConfigScene === 'cg');
                accountSceneCgButton.classList.toggle('border-[var(--bg-button)]', currentConfigScene === 'cg');
            }
            if (accountSceneYlButton) {
                accountSceneYlButton.classList.toggle('bg-[var(--bg-button)]', currentConfigScene === 'yl');
                accountSceneYlButton.classList.toggle('text-[var(--text-button)]', currentConfigScene === 'yl');
                accountSceneYlButton.classList.toggle('border-[var(--bg-button)]', currentConfigScene === 'yl');
            }
        }

        function setAccountConfigScene(scene) {
            const nextScene = normalizeAccountScene(scene);
            if (currentConfigScene === nextScene) {
                refreshAccountSceneButtons();
                return;
            }
            currentConfigScene = nextScene;
            localStorage.setItem('account_config_scene', currentConfigScene);
            refreshAccountSceneButtons();
            if (canManageSystemConfigs) {
                getBaseHot();
                getStandardWordMappingsConfig();
            }
        }

        async function updataBasehandle(params) {
            if (!textareahandle) {
                return;
            }
            const response = await fetch(`/tool/speakr/api/system-configs/end_phrase_patterns`, {
                method: "PUT",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    config_value: textareahandlecot,
                }),
            });
            const data = await response.json();
            if (!response.ok)
                throw new Error(data.error || "Failed to create share link");
            //   console.log(data.summary, "接收到回参");

        }
        async function getBasehandle(params) {
            const response = await fetch(
                `/tool/speakr/api/system-configs/end_phrase_patterns`,
                {
                    method: "GET",
                }
            );
            const data = await response.json();
            if (response.ok) {
                let res = data?.config?.config_value || ''
                updateTextareahandleValue(res)
            }

        }
        const standardWordMappingsList = document.getElementById('standardWordMappingsList');
        const standardWordMappingsEmpty = document.getElementById('standardWordMappingsEmpty');
        const standardWordMappingsCount = document.getElementById('standardWordMappingsCount');
        const standardWordImportPanel = document.getElementById('standardWordImportPanel');
        const standardWordMappingsBulkInput = document.getElementById('standardWordMappingsBulkInput');
        const addStandardWordMappingRowButton = document.getElementById('addStandardWordMappingRow');
        const toggleStandardWordImportPanelButton = document.getElementById('toggleStandardWordImportPanel');
        const closeStandardWordImportPanelButton = document.getElementById('closeStandardWordImportPanel');
        const appendStandardWordMappingsFromBulkButton = document.getElementById('appendStandardWordMappingsFromBulk');
        const replaceStandardWordMappingsFromBulkButton = document.getElementById('replaceStandardWordMappingsFromBulk');
        const clearStandardWordMappingsBulkInputButton = document.getElementById('clearStandardWordMappingsBulkInput');
        const copyStandardWordMappingsTextButton = document.getElementById('copyStandardWordMappingsText');
        const clearAllStandardWordMappingsButton = document.getElementById('clearAllStandardWordMappings');
        let draggedStandardWordMappingRow = null;

        function splitStandardWordVariants(rawValue) {
            return String(rawValue || '')
                .split(/[\s、，,]+/)
                .map(item => item.trim())
                .filter(Boolean);
        }

        function normalizeStandardWordMappings(mappings) {
            if (!Array.isArray(mappings)) {
                return [];
            }

            return mappings
                .map((mapping) => {
                    const standard = String(
                        mapping?.standard ?? mapping?.standard_word ?? ''
                    ).trim();
                    const variants = Array.isArray(mapping?.variants)
                        ? mapping.variants
                        : splitStandardWordVariants(
                            mapping?.variants ?? mapping?.common_words ?? ''
                        );

                    const deduplicatedVariants = [...new Set(
                        variants
                            .map((variant) => String(variant || '').trim())
                            .filter((variant) => variant && variant !== standard)
                    )];

                    if (!standard || !deduplicatedVariants.length) {
                        return null;
                    }

                    return {
                        standard,
                        variants: deduplicatedVariants
                    };
                })
                .filter(Boolean);
        }

        function parseStandardWordMappingsConfig(rawValue) {
            if (!rawValue || typeof rawValue !== 'string') {
                return [];
            }

            const trimmedValue = rawValue.trim();
            if (!trimmedValue) {
                return [];
            }

            if (trimmedValue.startsWith('[') || trimmedValue.startsWith('{')) {
                try {
                    const parsed = JSON.parse(trimmedValue);
                    if (Array.isArray(parsed)) {
                        return normalizeStandardWordMappings(parsed);
                    }
                    if (parsed && typeof parsed === 'object') {
                        return normalizeStandardWordMappings([parsed]);
                    }
                } catch (error) {
                    console.warn('解析标准词映射 JSON 失败，将尝试按文本格式解析', error);
                }
            }

            const mappings = trimmedValue
                .split('\n')
                .map((line) => {
                    const normalizedLine = line.trim();
                    if (!normalizedLine) {
                        return null;
                    }

                    const separator = normalizedLine.includes('：')
                        ? '：'
                        : normalizedLine.includes(':')
                            ? ':'
                            : null;

                    if (!separator) {
                        return null;
                    }

                    const separatorIndex = normalizedLine.indexOf(separator);
                    const standard = normalizedLine.slice(0, separatorIndex).trim();
                    const variantsValue = normalizedLine.slice(separatorIndex + 1).trim();
                    return {
                        standard,
                        variants: splitStandardWordVariants(variantsValue)
                    };
                })
                .filter(Boolean);

            return normalizeStandardWordMappings(mappings);
        }

        function setStandardWordImportPanelVisible(visible) {
            if (!standardWordImportPanel) {
                return;
            }

            standardWordImportPanel.classList.toggle('hidden', !visible);
        }

        function updateStandardWordMappingsEmptyState() {
            if (!standardWordMappingsList || !standardWordMappingsEmpty || !standardWordMappingsCount) {
                return;
            }

            const rows = standardWordMappingsList.querySelectorAll('.standard-word-mapping-row');
            const hasRows = rows.length > 0;
            standardWordMappingsEmpty.classList.toggle('hidden', hasRows);
            standardWordMappingsCount.textContent = `${rows.length} 条`;
        }

        function refreshStandardWordMappingRowState() {
            if (!standardWordMappingsList) {
                return;
            }

            const rows = Array.from(
                standardWordMappingsList.querySelectorAll('.standard-word-mapping-row')
            );

            rows.forEach((row, index) => {
                const orderBadge = row.querySelector('.standard-word-row-order');
                const moveUpButton = row.querySelector('.move-standard-word-mapping-up');
                const moveDownButton = row.querySelector('.move-standard-word-mapping-down');

                if (orderBadge) {
                    orderBadge.textContent = `#${index + 1}`;
                }

                if (moveUpButton) {
                    moveUpButton.disabled = index === 0;
                    moveUpButton.classList.toggle('opacity-50', index === 0);
                    moveUpButton.classList.toggle('cursor-not-allowed', index === 0);
                }

                if (moveDownButton) {
                    const isLast = index === rows.length - 1;
                    moveDownButton.disabled = isLast;
                    moveDownButton.classList.toggle('opacity-50', isLast);
                    moveDownButton.classList.toggle('cursor-not-allowed', isLast);
                }
            });

            updateStandardWordMappingsEmptyState();
        }

        function moveStandardWordMappingRow(row, direction) {
            if (!row || !standardWordMappingsList) {
                return;
            }

            if (direction < 0 && row.previousElementSibling) {
                standardWordMappingsList.insertBefore(row, row.previousElementSibling);
            } else if (direction > 0 && row.nextElementSibling) {
                standardWordMappingsList.insertBefore(row.nextElementSibling, row);
            }

            refreshStandardWordMappingRowState();
        }

        function serializeStandardWordMappingsToText(mappings) {
            return normalizeStandardWordMappings(mappings)
                .map((mapping) => `${mapping.standard}：${mapping.variants.join('、')}`)
                .join('\n');
        }

        async function copyStandardWordMappingsText() {
            const textValue = serializeStandardWordMappingsToText(collectStandardWordMappings());

            if (!textValue) {
                showToast('暂无可复制的标准词映射', 'error');
                return;
            }

            try {
                if (navigator?.clipboard?.writeText) {
                    await navigator.clipboard.writeText(textValue);
                } else {
                    const tempTextarea = document.createElement('textarea');
                    tempTextarea.value = textValue;
                    document.body.appendChild(tempTextarea);
                    tempTextarea.select();
                    document.execCommand('copy');
                    tempTextarea.remove();
                }
                showToast('标准词映射文本已复制', 'success');
            } catch (error) {
                console.error('复制标准词映射失败', error);
                showToast('复制失败，请手动复制', 'error');
            }
        }

        function clearAllStandardWordMappings() {
            if (!standardWordMappingsList) {
                return;
            }

            const rows = standardWordMappingsList.querySelectorAll('.standard-word-mapping-row');
            if (!rows.length) {
                showToast('暂无可删除的标准词映射', 'error');
                return;
            }

            const confirmed = window.confirm(
                `确定要批量删除全部 ${rows.length} 条标准词映射吗？保存设置后将生效。`
            );
            if (!confirmed) {
                return;
            }

            renderStandardWordMappings([]);
            showToast('已清空全部标准词映射，请保存设置以生效', 'success');
        }

        function importStandardWordMappings(mode = 'append') {
            const importedMappings = parseStandardWordMappingsConfig(
                standardWordMappingsBulkInput?.value || ''
            );

            if (!importedMappings.length) {
                showToast('未解析到有效映射，请检查导入格式', 'error');
                return;
            }

            const currentMappings = mode === 'replace'
                ? []
                : collectStandardWordMappings();

            renderStandardWordMappings([...currentMappings, ...importedMappings]);
            setStandardWordImportPanelVisible(false);
            showToast(
                mode === 'replace'
                    ? `已覆盖导入 ${importedMappings.length} 条映射`
                    : `已追加导入 ${importedMappings.length} 条映射`,
                'success'
            );
        }

        function createStandardWordMappingRow(mapping = {}) {
            const row = document.createElement('div');
            row.className =
                'standard-word-mapping-row grid grid-cols-1 md:grid-cols-[110px_minmax(0,1fr)_minmax(0,2fr)_150px] gap-3 items-start rounded-lg border border-[var(--border-primary)] bg-[var(--bg-secondary)] p-4';

            row.innerHTML = `
                <div>
                    <label class="block text-sm font-medium text-[var(--text-muted)] mb-2 md:hidden">排序</label>
                    <div class="flex items-center gap-2 md:flex-col md:items-start">
                        <button
                            type="button"
                            class="drag-standard-word-mapping inline-flex items-center justify-center w-9 h-9 rounded-md border border-[var(--border-primary)] text-[var(--text-muted)] cursor-grab active:cursor-grabbing"
                            title="拖拽排序"
                        >
                            <i class="fas fa-grip-vertical"></i>
                        </button>
                        <span
                            class="standard-word-row-order inline-flex items-center px-2 py-1 rounded-md text-xs font-medium bg-[var(--bg-tertiary)] text-[var(--text-secondary)] border border-[var(--border-primary)]"
                        >
                            #1
                        </span>
                    </div>
                </div>
                <div>
                    <label class="block text-sm font-medium text-[var(--text-muted)] mb-2">标准词</label>
                    <input
                        type="text"
                        class="standard-word-standard-input block w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md shadow-sm focus:outline-none focus:ring-[var(--border-focus)] focus:border-[var(--border-focus)] sm:text-sm bg-[var(--bg-input)] text-[var(--text-primary)]"
                        placeholder="例如：OpenAI"
                    >
                </div>
                <div>
                    <label class="block text-sm font-medium text-[var(--text-muted)] mb-2">常用词</label>
                    <input
                        type="text"
                        class="standard-word-variants-input block w-full px-3 py-2 border border-[var(--border-secondary)] rounded-md shadow-sm focus:outline-none focus:ring-[var(--border-focus)] focus:border-[var(--border-focus)] sm:text-sm bg-[var(--bg-input)] text-[var(--text-primary)]"
                        placeholder="例如：欧喷AI、欧彭AI 或 欧喷AI 欧彭AI"
                    >
                </div>
                <div>
                    <label class="block text-sm font-medium text-[var(--text-muted)] mb-2 md:hidden">操作</label>
                    <div class="flex items-center gap-2 md:flex-col md:items-stretch">
                        <button
                            type="button"
                            class="move-standard-word-mapping-up inline-flex items-center justify-center px-3 py-2 text-sm rounded-md border border-[var(--border-primary)] text-[var(--text-secondary)] hover:bg-[var(--bg-tertiary)] transition-colors duration-200"
                            title="上移"
                        >
                            <i class="fas fa-arrow-up"></i>
                        </button>
                        <button
                            type="button"
                            class="move-standard-word-mapping-down inline-flex items-center justify-center px-3 py-2 text-sm rounded-md border border-[var(--border-primary)] text-[var(--text-secondary)] hover:bg-[var(--bg-tertiary)] transition-colors duration-200"
                            title="下移"
                        >
                            <i class="fas fa-arrow-down"></i>
                        </button>
                        <button
                            type="button"
                            class="remove-standard-word-mapping inline-flex items-center justify-center px-3 py-2 text-sm rounded-md border border-[var(--border-primary)] text-[var(--text-secondary)] hover:text-[var(--text-danger)] hover:border-[var(--text-danger)] transition-colors duration-200"
                        >
                            <i class="fas fa-trash-alt md:mr-0 mr-2"></i><span class="md:hidden">删除</span>
                        </button>
                    </div>
                </div>
            `;

            row.querySelector('.standard-word-standard-input').value = mapping.standard || '';
            row.querySelector('.standard-word-variants-input').value = Array.isArray(mapping.variants)
                ? mapping.variants.join('、')
                : '';

            row.querySelector('.remove-standard-word-mapping').addEventListener('click', () => {
                row.remove();
                refreshStandardWordMappingRowState();
            });
            row.querySelector('.move-standard-word-mapping-up').addEventListener('click', () => {
                moveStandardWordMappingRow(row, -1);
            });
            row.querySelector('.move-standard-word-mapping-down').addEventListener('click', () => {
                moveStandardWordMappingRow(row, 1);
            });

            const dragHandle = row.querySelector('.drag-standard-word-mapping');
            dragHandle.draggable = true;

            dragHandle.addEventListener('dragstart', (event) => {
                draggedStandardWordMappingRow = row;
                row.classList.add('opacity-60', 'ring-2', 'ring-[var(--border-focus)]');
                if (event.dataTransfer) {
                    event.dataTransfer.effectAllowed = 'move';
                    event.dataTransfer.setData('text/plain', mapping.standard || '');
                }
            });

            dragHandle.addEventListener('dragend', () => {
                draggedStandardWordMappingRow = null;
                row.classList.remove('opacity-60', 'ring-2', 'ring-[var(--border-focus)]');
                refreshStandardWordMappingRowState();
            });

            row.addEventListener('dragover', (event) => {
                if (!draggedStandardWordMappingRow || draggedStandardWordMappingRow === row) {
                    return;
                }

                event.preventDefault();
                const rect = row.getBoundingClientRect();
                const shouldInsertBefore = event.clientY < rect.top + rect.height / 2;
                if (shouldInsertBefore) {
                    standardWordMappingsList.insertBefore(draggedStandardWordMappingRow, row);
                } else {
                    standardWordMappingsList.insertBefore(
                        draggedStandardWordMappingRow,
                        row.nextElementSibling
                    );
                }
            });

            return row;
        }

        function renderStandardWordMappings(mappings = []) {
            if (!standardWordMappingsList) {
                return;
            }

            standardWordMappingsList.innerHTML = '';

            const normalizedMappings = normalizeStandardWordMappings(mappings);
            normalizedMappings.forEach((mapping) => {
                standardWordMappingsList.appendChild(createStandardWordMappingRow(mapping));
            });

            refreshStandardWordMappingRowState();
        }

        function collectStandardWordMappings() {
            if (!standardWordMappingsList) {
                return [];
            }

            const mappings = Array.from(
                standardWordMappingsList.querySelectorAll('.standard-word-mapping-row')
            ).map((row) => ({
                standard: row.querySelector('.standard-word-standard-input')?.value || '',
                variants: splitStandardWordVariants(
                    row.querySelector('.standard-word-variants-input')?.value || ''
                )
            }));

            return normalizeStandardWordMappings(mappings);
        }

        async function updateStandardWordMappingsConfig() {
            if (!standardWordMappingsList) {
                return;
            }

            const mappings = collectStandardWordMappings();
            const response = await fetch(`/tool/speakr/api/system-configs/${getStandardWordMappingsConfigKey()}`, {
                method: "PUT",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    config_value: JSON.stringify(mappings),
                    description: "实时转录后处理中用于纠错后标准化替换的标准词映射"
                }),
            });
            const data = await response.json();
            if (!response.ok) {
                throw new Error(data.error || "Failed to update standard word mappings");
            }
        }

        async function getStandardWordMappingsConfig() {
            if (!standardWordMappingsList) {
                return;
            }

            const response = await fetch(`/tool/speakr/api/system-configs/${getStandardWordMappingsConfigKey()}`, {
                method: "GET",
            });
            const data = await response.json();
            if (response.ok) {
                renderStandardWordMappings(
                    parseStandardWordMappingsConfig(data?.config?.config_value || '')
                );
                return;
            }

            renderStandardWordMappings([]);
        }

        if (toggleStandardWordImportPanelButton) {
            toggleStandardWordImportPanelButton.addEventListener('click', () => {
                const willShow = standardWordImportPanel?.classList.contains('hidden');
                setStandardWordImportPanelVisible(willShow);
                if (willShow) {
                    standardWordMappingsBulkInput?.focus();
                }
            });
        }

        if (closeStandardWordImportPanelButton) {
            closeStandardWordImportPanelButton.addEventListener('click', () => {
                setStandardWordImportPanelVisible(false);
            });
        }

        if (appendStandardWordMappingsFromBulkButton) {
            appendStandardWordMappingsFromBulkButton.addEventListener('click', () => {
                importStandardWordMappings('append');
            });
        }

        if (replaceStandardWordMappingsFromBulkButton) {
            replaceStandardWordMappingsFromBulkButton.addEventListener('click', () => {
                importStandardWordMappings('replace');
            });
        }

        if (clearStandardWordMappingsBulkInputButton) {
            clearStandardWordMappingsBulkInputButton.addEventListener('click', () => {
                if (standardWordMappingsBulkInput) {
                    standardWordMappingsBulkInput.value = '';
                    standardWordMappingsBulkInput.focus();
                }
            });
        }

        if (copyStandardWordMappingsTextButton) {
            copyStandardWordMappingsTextButton.addEventListener('click', () => {
                copyStandardWordMappingsText();
            });
        }

        if (clearAllStandardWordMappingsButton) {
            clearAllStandardWordMappingsButton.addEventListener('click', () => {
                clearAllStandardWordMappings();
            });
        }

        if (addStandardWordMappingRowButton) {
            addStandardWordMappingRowButton.addEventListener('click', () => {
                standardWordMappingsList?.appendChild(createStandardWordMappingRow());
                refreshStandardWordMappingRowState();
            });
        }
        const openBtn = document.getElementById('openPromptModal');
        const modal = document.getElementById('promptModal');
        const cancelBtnprompt = document.getElementById('cancelPrompt');
        const confirmBtn = document.getElementById('confirmPrompt');
        const promptListEl = document.getElementById('promptList');


        // 保存当前选中的 prompt id
        let selectedPromptId = localStorage.getItem('selected_prompt_id') || null;


        // 打开弹框
        openBtn.onclick = async () => {
            modal.classList.remove('hidden');
            await loadPromptList();
        };


        // 关闭弹框
        cancelBtnprompt.onclick = () => modal.classList.add('hidden');


        // 确认选择
        confirmBtn.onclick = () => {
            const checkedRadio = document.querySelector('input[name="prompt_radio"]:checked');
            if (checkedRadio) {
                selectedPromptId = checkedRadio.value;
                localStorage.setItem('selected_prompt_id', selectedPromptId);


                // 显示选中的名称到 textarea
                const selectedName = checkedRadio.getAttribute('data-name');
                document.getElementById('promptTextarea').value = selectedName;
            }
            modal.classList.add('hidden');
        };


        // 加载 Prompt 列表
        async function loadPromptList() {
            promptListEl.innerHTML = '<p class="text-sm text-gray-500">加载中...</p>';


            try {
                const response = await fetch(`/tool/speakr/api/external/prompts/list`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ skip: 0, limit: 999 })
                });


                const data = await response.json();


                // 渲染列表
                promptListEl.innerHTML = '';


              data.prompt_list.forEach(item => {
  const row = document.createElement('div');

  row.className = "grid grid-cols-[50px_350px] px-2 py-2 items-start gap-2 bg-[#1f2937] rounded";

  row.innerHTML = `
    <div class="flex justify-center items-start pt-1">
      <input type="radio"
        name="prompt_radio"
        value="${item.id}"
        data-name="${item.name}"
        ${selectedPromptId == item.id ? 'checked' : ''}>
    </div>

    <div class="whitespace-normal break-words leading-5">
      ${item.name}
    </div>
  `;

  promptList.appendChild(row);
});
            } catch (err) {
                promptListEl.innerHTML = '<p class="text-red-500 text-sm">加载失败</p>';
            }
        }
        if (accountSceneCgButton) {
            accountSceneCgButton.addEventListener('click', () => setAccountConfigScene('cg'));
        }
        if (accountSceneYlButton) {
            accountSceneYlButton.addEventListener('click', () => setAccountConfigScene('yl'));
        }
        refreshAccountSceneButtons();
        if (canManageSystemConfigs) {
            getBaseHot()
            getBasehandle()
            getStandardWordMappingsConfig()
        }
        // getBasePrompt()
        function updateTextareaValue(newValue) {
            if (!textarea) {
                return;
            }
            // 设置新值
            textarea.value = newValue;
            // 手动触发input事件（让监听器感知到值变化）
            textarea.dispatchEvent(new Event('input'));
        }
        function updateTextareahandleValue(newValue) {
            if (!textareahandle) {
                return;
            }
            // 设置新值
            textareahandle.value = newValue;
            // 手动触发input事件（让监听器感知到值变化）
            textareahandle.dispatchEvent(new Event('input'));
        }
        function updatePromptValue(newValue) {
            // 设置新值
            textareaHandelPrompt.value = newValue;
            // 手动触发input事件（让监听器感知到值变化）
            textareaHandelPrompt.dispatchEvent(new Event('input'));
        }
        if (accountInfoForm) {
            accountInfoForm.addEventListener('submit', async (e) => {
                e.preventDefault();
                const formData = new FormData(accountInfoForm);
                console.log(formData, 'formData');

                try {
                    if (canManageSystemConfigs) {
                        await Promise.all([
                            updataBaseHot(),
                            updataBasehandle(),
                            updateStandardWordMappingsConfig()
                        ]);
                    }

                    const response = await fetch('/tool/speakr/account', {
                        method: 'POST',
                        body: formData
                    });

                    if (response.ok) {
                        if (canManageSystemConfigs) {
                            getBaseHot()
                            getBasehandle()
                            getStandardWordMappingsConfig()
                        }

                        showToast('Account information updated successfully', 'success');
                    } else {
                        const text = await response.text();
                        showToast('Failed to update account information', 'error');
                    }
                } catch (error) {
                    showToast('Network error: ' + error.message, 'error');
                }
            });
        }

        // AJAX form submission for Custom Prompts
        const customPromptsForm = document.getElementById('customPromptsForm');
        if (customPromptsForm) {
            customPromptsForm.addEventListener('submit', async (e) => {
                e.preventDefault();

                const formData = new FormData(customPromptsForm);

                try {
                    const response = await fetch('/tool/speakr/account', {
                        method: 'POST',
                        body: formData
                    });

                    if (response.ok) {
                        showToast('Custom prompt saved successfully', 'success');
                    } else {
                        const text = await response.text();
                        showToast('Failed to save custom prompt', 'error');
                    }
                } catch (error) {
                    showToast('Network error: ' + error.message, 'error');
                }
            });
        }

        // Check for stored tab preference (from language change reload)
        const storedTab = localStorage.getItem('activeAccountTab');
        if (storedTab) {
            localStorage.removeItem('activeAccountTab'); // Clean up after use
        }

        // Check for URL hash and show appropriate tab
        const urlHash = window.location.hash.substring(1); // Remove the '#' symbol
        if (urlHash === 'prompts') {
            showPromptsTab();
        } else if (urlHash === 'tags') {
            showTagsTab();
        } else if (urlHash === 'shares') {
            showSharesTab();
        } else if (urlHash === 'shares') {
            showSharesTab();
        } else if (urlHash === 'voiceprint') {
            showVoiceprint();
        } else if (storedTab) {
            // Restore previously active tab after language change
            if (storedTab === 'prompts') {
                showPromptsTab();
            } else if (storedTab === 'tags') {
                showTagsTab();
            } else if (storedTab === 'shares') {
                showSharesTab();
            } else if (storedTab === 'about') {
                showAboutTab();
            } else if (storedTab === 'voiceprint') {
                showVoiceprint();
            } else {
                showAccountTab();
            }
        } else {
            // Default to account tab
            showAccountTab();
        }

        // Track original UI language to detect changes
        let currentUILanguage = document.getElementById('ui_language').value;
        const originalUILanguage = currentUILanguage;

        // Add immediate language change listener to the UI language dropdown
        const uiLanguageSelect = document.getElementById('ui_language');
        if (uiLanguageSelect) {
            uiLanguageSelect.addEventListener('change', async function (e) {
                const newLanguage = e.target.value;
                if (newLanguage !== currentUILanguage) {
                    await changeLanguageImmediately(newLanguage);
                    // Update the current language tracker
                    currentUILanguage = newLanguage;
                }
            });
        }

        // Add event listener to the account info form
        document.getElementById('accountInfoForm').addEventListener('submit', function (e) {
            const newUILanguage = document.getElementById('ui_language').value;
            if (newUILanguage !== originalUILanguage) {
                // Language has changed, store flag to reload main app
                localStorage.setItem('ui_language_changed', 'true');
                localStorage.setItem('preferredLanguage', newUILanguage);
            }
        });

        // Template Management Functions
        let templates = [];
        let currentTemplate = null;
        let isEditingTemplate = false;

        async function loadTemplates() {
            try {
                const response = await fetch('/tool/speakr/api/transcript-templates');
                if (!response.ok) {
                    throw new Error('Failed to load templates');
                }
                templates = await response.json();

                // Create default templates if none exist
                if (templates.length === 0) {
                    document.getElementById('createDefaultTemplatesBtn').style.display = 'block';
                } else {
                    document.getElementById('createDefaultTemplatesBtn').style.display = 'none';
                }

                renderTemplatesList();
            } catch (error) {
                console.error('Error loading templates:', error);
                showToast('Failed to load templates', 'error');
            }
        }

        function renderTemplatesList() {
            const templatesList = document.getElementById('templatesList');
            templatesList.innerHTML = '';

            if (templates.length === 0) {
                templatesList.innerHTML = '<p class="text-sm text-[var(--text-muted)] text-center py-4">暂无模板</p>';
                return;
            }

            templates.forEach(template => {
                const templateItem = document.createElement('div');
                templateItem.className = 'p-3 bg-[var(--bg-primary)] rounded-md hover:bg-[var(--bg-tertiary)] cursor-pointer transition-colors border border-[var(--border-primary)]';
                if (template.is_default) {
                    templateItem.className += ' ring-2 ring-[var(--ring-focus)]';
                }

                templateItem.innerHTML = `
                    <div class="flex items-start justify-between">
                        <div class="flex-1">
                            <h4 class="text-sm font-medium text-[var(--text-primary)]">${template.name}</h4>
                            ${template.description ? `<p class="text-xs text-[var(--text-muted)] mt-1">${template.description}</p>` : ''}
                            ${template.is_default ? '<span class="text-xs text-[var(--text-accent)] mt-1"><i class="fas fa-star mr-1"></i>Default</span>' : ''}
                        </div>
                    </div>
                `;

                templateItem.addEventListener('click', () => selectTemplate(template));
                templatesList.appendChild(templateItem);
            });
        }

        function selectTemplate(template) {
            currentTemplate = template;
            isEditingTemplate = true;

            // Show editor, hide empty state
            document.getElementById('templateEditor').classList.remove('hidden');
            document.getElementById('templateEmptyState').classList.add('hidden');

            // Populate form
            document.getElementById('templateName').value = template.name;
            document.getElementById('templateDescription').value = template.description || '';
            document.getElementById('templateContent').value = template.template;
            document.getElementById('templateIsDefault').checked = template.is_default;

            // Show delete button
            document.getElementById('deleteTemplateBtn').classList.remove('hidden');
        }

        function createNewTemplate() {
            
            currentTemplate = null;
            isEditingTemplate = false;

            // Show editor, hide empty state
            document.getElementById('templateEditor').classList.remove('hidden');
            document.getElementById('templateEmptyState').classList.add('hidden');

            // Clear form
            document.getElementById('templateForm').reset();

            // Hide delete button
            document.getElementById('deleteTemplateBtn').classList.add('hidden');
        }

        document.getElementById('createTemplateBtn')?.addEventListener('click', createNewTemplate);

        document.getElementById('cancelTemplateBtn')?.addEventListener('click', () => {
            // Hide editor, show empty state
            document.getElementById('templateEditor').classList.add('hidden');
            document.getElementById('templateEmptyState').classList.remove('hidden');
            currentTemplate = null;
            isEditingTemplate = false;
        });

        document.getElementById('templateForm')?.addEventListener('submit', async (e) => {
            e.preventDefault();

            const templateData = {
                name: document.getElementById('templateName').value,
                description: document.getElementById('templateDescription').value,
                template: document.getElementById('templateContent').value,
                is_default: document.getElementById('templateIsDefault').checked
            };

            try {
                const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
                const url = isEditingTemplate ? `/tool/speakr/api/transcript-templates/${currentTemplate.id}` : '/tool/speakr/api/transcript-templates';
                const method = isEditingTemplate ? 'PUT' : 'POST';

                const response = await fetch(url, {
                    method: method,
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRFToken': csrfToken
                    },
                    body: JSON.stringify(templateData)
                });

                if (!response.ok) {
                    const errorData = await response.json();
                    throw new Error(errorData.error || 'Failed to save template');
                }

                const savedTemplate = await response.json();

                if (isEditingTemplate) {
                    // Update existing template
                    const index = templates.findIndex(t => t.id === savedTemplate.id);
                    if (index !== -1) {
                        templates[index] = savedTemplate;
                    }
                } else {
                    // Add new template
                    templates.push(savedTemplate);
                }

                // Update default status for other templates if needed
                if (savedTemplate.is_default) {
                    templates.forEach(t => {
                        if (t.id !== savedTemplate.id) {
                            t.is_default = false;
                        }
                    });
                }

                renderTemplatesList();
                showToast(isEditingTemplate ? 'Template updated successfully' : 'Template created successfully', 'success');

                // Hide editor
                document.getElementById('templateEditor').classList.add('hidden');
                document.getElementById('templateEmptyState').classList.remove('hidden');
                currentTemplate = null;
                isEditingTemplate = false;
            } catch (error) {
                console.error('Error saving template:', error);
                showToast(error.message || 'Failed to save template', 'error');
            }
        });

        document.getElementById('deleteTemplateBtn')?.addEventListener('click', async () => {
            if (!currentTemplate || !confirm('Are you sure you want to delete this template?')) {
                return;
            }

            try {
                const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
                const response = await fetch(`/tool/speakr/api/transcript-templates/${currentTemplate.id}`, {
                    method: 'DELETE',
                    headers: {
                        'X-CSRFToken': csrfToken
                    }
                });

                if (!response.ok) {
                    throw new Error('Failed to delete template');
                }

                // Remove from local array
                templates = templates.filter(t => t.id !== currentTemplate.id);
                renderTemplatesList();

                // Hide editor
                document.getElementById('templateEditor').classList.add('hidden');
                document.getElementById('templateEmptyState').classList.remove('hidden');
                currentTemplate = null;
                isEditingTemplate = false;

                showToast('Template deleted successfully', 'success');
            } catch (error) {
                console.error('Error deleting template:', error);
                showToast('Failed to delete template', 'error');
            }
        });

        document.getElementById('createDefaultTemplatesBtn')?.addEventListener('click', async () => {
            try {
                const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
                const response = await fetch('/tool/speakr/api/transcript-templates/create-defaults', {
                    method: 'POST',
                    headers: {
                        'X-CSRFToken': csrfToken
                    }
                });

                if (!response.ok) {
                    throw new Error('Failed to create default templates');
                }

                const result = await response.json();
                templates = result.templates;
                renderTemplatesList();
                showToast('Default templates created successfully', 'success');
            } catch (error) {
                console.error('Error creating default templates:', error);
                showToast('Failed to create default templates', 'error');
            }
        });

        function showToast(message, type = 'info') {
            // Simple toast notification
            const toast = document.createElement('div');
            toast.className = `fixed bottom-4 right-4 px-4 py-2 rounded-md text-white z-50 ${type === 'success' ? 'bg-green-600' :
                type === 'error' ? 'bg-red-600' :
                    'bg-blue-600'
                }`;
            toast.textContent = message;
            document.body.appendChild(toast);

            setTimeout(() => {
                toast.remove();
            }, 3000);
        }
    });
    </script>
</body>
<style scoped>
    :root {
        --text-primarys: #333;
        --btn-primarys: #4f46e5;
        --btn-dangers: #dc2626;
        --bg-modals: rgba(0, 0, 0, 0.5);
        /* --border-color: #e5e7eb; */
    }

    body {
        font-family: Arial, sans-serif;
        /* margin: 20px; */
        /* background: #f9f9f9; */
    }

    .btn {
        padding: 6px 12px;
        border: none;
        border-radius: 4px;
        cursor: pointer;
        color: white;
    }

    .btn-primary {
        background: var(--btn-primarys);
    }

    .btn-danger {
        background: var(--btn-dangers);
    }

    .btn-icon {
        background: none;
        padding: 4px;
        cursor: pointer;
    }

    table {
        width: 100%;
        border-collapse: collapse;
        background: white;
        border: 1px solid var(--border-colors);
        border-radius: 6px;
        overflow: hidden;
    }

    th,
    td {
        text-align: left;
        padding: 12px;
        border-bottom: 1px solid var(--border-colors);
        color: #000;
    }

    th {
        background: #f3f4f6;
        color: #000;

    }

    .top-bar {
        display: flex;
        justify-content: flex-end;
        margin-bottom: 12px;
    }

    .modal {
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: var(--bg-modals);
        justify-content: center;
        align-items: center;
        z-index: 1000;
    }

    .modal-content {
        background: white;
        padding: 20px;
        border-radius: 8px;
        width: 400px;
    }

    .modal-header {
        font-size: 18px;
        font-weight: bold;
        margin-bottom: 16px;
    }

    .modal-footer {
        text-align: right;
        margin-top: 16px;
    }

    input,
    textarea {
        width: 100%;
        padding: 6px;
        margin-bottom: 12px;
        border: 1px solid #d1d5db;
        border-radius: 4px;
    }

    audio {
        width: 100%;
        margin-bottom: 12px;
    }

    /* ===== 弹框整体样式优化 ===== */
    #voiceModal {
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: rgba(0, 0, 0, 0.45);
        justify-content: center;
        align-items: center;
        z-index: 1000;
        font-family: "Microsoft YaHei", sans-serif;
    }

    #voiceModal .modal-content {
        background: #fff;
        width: 420px;
        border-radius: 8px;
        box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
        padding: 20px 24px;
        color: #000;
        box-sizing: border-box;
    }

    /* ===== 标题样式 ===== */
    #voiceModal .modal-header {
        font-size: 18px;
        font-weight: 600;
        color: #000;
        margin-bottom: 20px;
    }

    /* ===== 标签标题 ===== */
    #voiceModal .label-tit {
        font-size: 14px;
        font-weight: 500;
        color: #000;
        margin-bottom: 6px;
    }

    /* ===== 输入框、下拉框、文本域 ===== */
    #voiceModal input[type="file"],
    #voiceModal input[type="text"],
    #voiceModal textarea {
        width: 100%;
        padding: 8px 10px;
        border: 1px solid #d9d9d9;
        border-radius: 4px;
        box-sizing: border-box;
        font-size: 14px;
        color: #000;
        outline: none;
        transition: border-color 0.2s;
    }

    #voiceModal input[type="file"]:hover,
    #voiceModal input[type="text"]:hover,
    #voiceModal textarea:hover {
        border-color: #409eff;
    }

    #voiceModal input[type="file"]:focus,
    #voiceModal input[type="text"]:focus,
    #voiceModal textarea:focus {
        border-color: #409eff;
        box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
    }

    /* ===== 提示文字 ===== */
    #voiceModal .tips {
        font-size: 12px;
        color: #666;
        margin-top: 4px;
        margin-bottom: 16px;
        line-height: 1.4;
    }

    /* ===== 按钮样式 ===== */
    #voiceModal .modal-footer {
        display: flex;
        justify-content: flex-end;
        gap: 8px;
        margin-top: 16px;
    }

    #voiceModal .btn {
        padding: 6px 14px;
        border: 1px solid #d9d9d9;
        border-radius: 4px;
        background: #fff;
        cursor: pointer;
        font-size: 14px;
        transition: all 0.2s;
        color: #000;
    }

    #voiceModal .btn:hover {
        border-color: #bfbfbf;
        background: #f5f5f5;
    }

    #voiceModal .btn-primary {
        background: #1677ff;
        color: #fff !important;
        border-color: #1677ff;
    }

    #voiceModal .btn-primary:hover {
        background: #409eff;
    }

    /* ===== 录音按钮样式（普通与录音中状态） ===== */
    #voiceModal button[type="button"][onclick^="startRecording"] {
        margin-top: 6px;
        margin-bottom: 10px;
        padding: 6px 12px;
        font-size: 14px;
        border-radius: 4px;
        border: 1px solid #d9d9d9;
        background: #fff;
        color: #000;
        cursor: pointer;
        transition: all 0.2s;
    }

    #voiceModal button[type="button"][onclick^="startRecording"]:hover {
        border-color: #409eff;
        color: #409eff;
    }

    /* 录音中状态 */
    #voiceModal .btn-recording {
        background: #fff !important;
        color: #dc2626 !important;
        border: 1px solid #dc2626 !important;
        font-weight: 600;
    }

    #voiceModal .btn-recording::before {
        content: "⏹ ";
        color: #dc2626;
    }

    /* ===== 音频播放控件 ===== */
    #voiceModal audio {
        width: 100%;
        margin-top: 10px;
        margin-bottom: 10px;
    }

    /* ===== 输入框间距 ===== */
    #voiceModal input[type="text"],
    #voiceModal textarea,
    #voiceModal input[type="file"] {
        margin-bottom: 12px;
    }

    /* 录音中状态 */
    .btn-recording {
        background: #fff !important;
        color: #dc2626 !important;
        border: 1px solid #dc2626;
        font-weight: bold;
    }

    /* 录音时的红色方块动画效果（可选） */
    .btn-recording::before {
        content: "⏹ ";
        color: #dc2626;
    }

    /* 普通状态下的麦克风图标 */
    button#recordBtn::before {
        content: "🎤 ";
    }

    .file-box,
    .record-box {
        display: flex;
        align-items: center;
        gap: 8px;
        margin-bottom: 10px;
    }

    /* 清空按钮样式 */
    .btn-clear {
        padding: 4px 10px;
        border: 1px solid #d9d9d9;
        border-radius: 4px;
        background: #fff;
        color: #666;
        font-size: 13px;
        cursor: pointer;
        transition: all 0.2s;
    }

    .btn-clear:hover {
        border-color: #ff4d4f;
        color: #ff4d4f;
    }
</style>

</html>
