{"id":57,"date":"2025-07-30T02:24:11","date_gmt":"2025-07-29T18:24:11","guid":{"rendered":"https:\/\/blog.liu-qi.cn\/?p=57"},"modified":"2025-07-30T02:24:11","modified_gmt":"2025-07-29T18:24:11","slug":"%e5%bd%95%e9%9f%b3%e8%bd%ac%e6%96%87%e5%ad%97","status":"publish","type":"post","link":"https:\/\/en.blog.liu-qi.cn\/index.php\/2025\/07\/30\/%e5%bd%95%e9%9f%b3%e8%bd%ac%e6%96%87%e5%ad%97\/","title":{"rendered":"\u5f55\u97f3\u8f6c\u6587\u5b57"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>&lt;!DOCTYPE html>\n&lt;html lang=\"zh-CN\">\n&lt;head>\n    &lt;meta charset=\"UTF-8\">\n    &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    &lt;title>\u5f55\u97f3\u8f6c\u6587\u5b57&lt;\/title>\n    &lt;style>\n        * {\n            margin: 0;\n            padding: 0;\n            box-sizing: border-box;\n        }\n\n        body {\n            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n            min-height: 100vh;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            padding: 20px;\n        }\n\n        .container {\n            background: rgba(255, 255, 255, 0.95);\n            backdrop-filter: blur(10px);\n            border-radius: 20px;\n            padding: 40px;\n            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);\n            max-width: 700px;\n            width: 100%;\n        }\n\n        h1 {\n            text-align: center;\n            color: #333;\n            margin-bottom: 30px;\n            font-size: 2.5em;\n            background: linear-gradient(45deg, #667eea, #764ba2);\n            -webkit-background-clip: text;\n            -webkit-text-fill-color: transparent;\n        }\n\n        .config-section {\n            margin-bottom: 30px;\n            padding: 20px;\n            background: rgba(102, 126, 234, 0.1);\n            border-radius: 15px;\n            border-left: 4px solid #667eea;\n        }\n\n        .config-section h3 {\n            color: #333;\n            margin-bottom: 15px;\n        }\n\n        .input-group {\n            margin-bottom: 15px;\n        }\n\n        label {\n            display: block;\n            color: #555;\n            margin-bottom: 5px;\n            font-weight: 500;\n        }\n\n        input, select {\n            width: 100%;\n            padding: 12px;\n            border: 2px solid #ddd;\n            border-radius: 10px;\n            font-size: 16px;\n            transition: all 0.3s ease;\n        }\n\n        input:focus, select:focus {\n            outline: none;\n            border-color: #667eea;\n            box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);\n        }\n\n        small {\n            display: block;\n            margin-top: 5px;\n            color: #666;\n            font-size: 12px;\n        }\n\n        .record-section {\n            text-align: center;\n            margin: 30px 0;\n        }\n\n        .record-btn {\n            background: linear-gradient(45deg, #667eea, #764ba2);\n            color: white;\n            border: none;\n            padding: 20px 40px;\n            border-radius: 50px;\n            font-size: 18px;\n            font-weight: bold;\n            cursor: pointer;\n            transition: all 0.3s ease;\n            margin: 10px;\n            box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3);\n        }\n\n        .record-btn:hover {\n            transform: translateY(-3px);\n            box-shadow: 0 15px 35px rgba(102, 126, 234, 0.4);\n        }\n\n        .record-btn:active {\n            transform: translateY(0);\n        }\n\n        .record-btn.recording {\n            background: linear-gradient(45deg, #ff6b6b, #ee5a52);\n            animation: pulse 2s infinite;\n        }\n\n        @keyframes pulse {\n            0% { transform: scale(1); }\n            50% { transform: scale(1.05); }\n            100% { transform: scale(1); }\n        }\n\n        .status {\n            margin: 20px 0;\n            padding: 15px;\n            border-radius: 10px;\n            text-align: center;\n            font-weight: 500;\n        }\n\n        .status.info {\n            background: rgba(52, 152, 219, 0.1);\n            color: #2980b9;\n            border: 1px solid rgba(52, 152, 219, 0.3);\n        }\n\n        .status.success {\n            background: rgba(46, 204, 113, 0.1);\n            color: #27ae60;\n            border: 1px solid rgba(46, 204, 113, 0.3);\n        }\n\n        .status.error {\n            background: rgba(231, 76, 60, 0.1);\n            color: #c0392b;\n            border: 1px solid rgba(231, 76, 60, 0.3);\n        }\n\n        .result-section {\n            margin-top: 30px;\n        }\n\n        .result-text {\n            background: #f8f9fa;\n            border: 2px solid #e9ecef;\n            border-radius: 15px;\n            padding: 20px;\n            min-height: 120px;\n            font-size: 16px;\n            line-height: 1.6;\n            white-space: pre-wrap;\n            word-wrap: break-word;\n        }\n\n        .audio-player {\n            margin: 20px 0;\n            width: 100%;\n        }\n\n        .file-upload {\n            margin: 20px 0;\n            text-align: center;\n        }\n\n        .file-upload input&#91;type=\"file\"] {\n            display: none;\n        }\n\n        .file-upload label {\n            display: inline-block;\n            padding: 15px 30px;\n            background: linear-gradient(45deg, #28a745, #20c997);\n            color: white;\n            border-radius: 25px;\n            cursor: pointer;\n            transition: all 0.3s ease;\n            font-weight: bold;\n        }\n\n        .file-upload label:hover {\n            transform: translateY(-2px);\n            box-shadow: 0 10px 25px rgba(40, 167, 69, 0.3);\n        }\n\n        .speaker-timeline {\n            margin: 20px 0;\n            padding: 15px;\n            background: #f8f9fa;\n            border-radius: 10px;\n            border-left: 4px solid #667eea;\n        }\n\n        .speaker-segment {\n            margin: 8px 0;\n            padding: 10px;\n            border-radius: 8px;\n            position: relative;\n        }\n\n        .speaker-1 {\n            background: rgba(102, 126, 234, 0.1);\n            border-left: 3px solid #667eea;\n        }\n\n        .speaker-2 {\n            background: rgba(255, 107, 107, 0.1);\n            border-left: 3px solid #ff6b6b;\n        }\n\n        .speaker-3 {\n            background: rgba(46, 204, 113, 0.1);\n            border-left: 3px solid #2ecc71;\n        }\n\n        .speaker-4 {\n            background: rgba(241, 196, 15, 0.1);\n            border-left: 3px solid #f1c40f;\n        }\n\n        .speaker-label {\n            font-weight: bold;\n            color: #555;\n            margin-bottom: 5px;\n            font-size: 14px;\n        }\n\n        .speaker-time {\n            font-size: 12px;\n            color: #888;\n            margin-left: 10px;\n        }\n\n        .speaker-text {\n            margin-top: 5px;\n            line-height: 1.4;\n        }\n\n        .analysis-section {\n            margin: 20px 0;\n            padding: 15px;\n            background: rgba(52, 152, 219, 0.1);\n            border-radius: 10px;\n            border-left: 4px solid #3498db;\n        }\n\n        .toggle-section {\n            margin: 10px 0;\n        }\n\n        .toggle-btn {\n            background: #3498db;\n            color: white;\n            border: none;\n            padding: 8px 16px;\n            border-radius: 5px;\n            cursor: pointer;\n            font-size: 14px;\n        }\n\n        .toggle-btn:hover {\n            background: #2980b9;\n        }\n    &lt;\/style>\n&lt;\/head>\n&lt;body>\n    &lt;div class=\"container\">\n        &lt;h1>\ud83c\udf99\ufe0f \u5f55\u97f3\u8f6c\u6587\u5b57&lt;\/h1>\n        \n        &lt;!-- API\u914d\u7f6e\u533a\u57df -->\n        &lt;div class=\"config-section\">\n            &lt;h3>\u2699\ufe0f API\u914d\u7f6e&lt;\/h3>\n            &lt;div class=\"input-group\">\n                &lt;label for=\"apiProvider\">API\u670d\u52a1\u5546:&lt;\/label>\n                &lt;select id=\"apiProvider\">\n                    &lt;option value=\"siliconflow\">SiliconFlow (\u7eaf\u8f6c\u5199)&lt;\/option>\n                    &lt;option value=\"volcengine\">\u706b\u5c71\u5f15\u64ce (\u652f\u6301\u8bf4\u8bdd\u4eba\u5206\u79bb)&lt;\/option>\n                &lt;\/select>\n            &lt;\/div>\n            \n            &lt;!-- SiliconFlow\u914d\u7f6e -->\n            &lt;div id=\"siliconflowConfig\">\n                &lt;div class=\"input-group\">\n                    &lt;label for=\"apiUrl\">API\u5730\u5740:&lt;\/label>\n                    &lt;input type=\"text\" id=\"apiUrl\" value=\"https:\/\/api.siliconflow.cn\/v1\/audio\/transcriptions\">\n                &lt;\/div>\n                &lt;div class=\"input-group\">\n                    &lt;label for=\"apiKey\">API\u5bc6\u94a5:&lt;\/label>\n                    &lt;input type=\"password\" id=\"apiKey\" placeholder=\"\u8bf7\u8f93\u5165\u60a8\u7684SiliconFlow API\u5bc6\u94a5\">\n                &lt;\/div>\n                &lt;div class=\"input-group\">\n                    &lt;label for=\"model\">\u6a21\u578b:&lt;\/label>\n                    &lt;input type=\"text\" id=\"model\" value=\"FunAudioLLM\/SenseVoiceSmall\">\n                &lt;\/div>\n            &lt;\/div>\n            \n            &lt;!-- \u706b\u5c71\u5f15\u64ce\u914d\u7f6e -->\n            &lt;div id=\"volcengineConfig\" style=\"display: none;\">\n                &lt;div class=\"input-group\">\n                    &lt;label for=\"volcSubmitUrl\">\u63d0\u4ea4\u4efb\u52a1API:&lt;\/label>\n                    &lt;input type=\"text\" id=\"volcSubmitUrl\" value=\"https:\/\/openspeech.bytedance.com\/api\/v3\/auc\/bigmodel\/submit\">\n                &lt;\/div>\n                &lt;div class=\"input-group\">\n                    &lt;label for=\"volcQueryUrl\">\u67e5\u8be2\u7ed3\u679cAPI:&lt;\/label>\n                    &lt;input type=\"text\" id=\"volcQueryUrl\" value=\"https:\/\/openspeech.bytedance.com\/api\/v3\/auc\/bigmodel\/query\">\n                &lt;\/div>\n                &lt;div class=\"input-group\">\n                    &lt;label for=\"volcAppKey\">APP ID:&lt;\/label>\n                    &lt;input type=\"text\" id=\"volcAppKey\" placeholder=\"\u706b\u5c71\u5f15\u64ce\u63a7\u5236\u53f0\u83b7\u53d6\u7684APP ID\">\n                &lt;\/div>\n                &lt;div class=\"input-group\">\n                    &lt;label for=\"volcAccessKey\">Access Token:&lt;\/label>\n                    &lt;input type=\"password\" id=\"volcAccessKey\" placeholder=\"\u706b\u5c71\u5f15\u64ce\u63a7\u5236\u53f0\u83b7\u53d6\u7684Access Token\">\n                &lt;\/div>\n                \n                &lt;!-- \u97f3\u9891URL\u83b7\u53d6\u65b9\u5f0f\u9009\u62e9 -->\n                &lt;div class=\"input-group\">\n                    &lt;label for=\"audioUrlMethod\">\u97f3\u9891URL\u83b7\u53d6\u65b9\u5f0f:&lt;\/label>\n                    &lt;select id=\"audioUrlMethod\">\n                        &lt;option value=\"direct\">\u76f4\u63a5\u8f93\u5165\u97f3\u9891URL&lt;\/option>\n                        &lt;option value=\"upload\">\u901a\u8fc7\u4e0a\u4f20\u670d\u52a1\u83b7\u53d6URL&lt;\/option>\n                    &lt;\/select>\n                &lt;\/div>\n                \n                &lt;!-- \u76f4\u63a5\u8f93\u5165URL\u9009\u9879 -->\n                &lt;div id=\"directUrlConfig\">\n                    &lt;div class=\"input-group\" style=\"background: rgba(46, 204, 113, 0.1); padding: 15px; border-radius: 8px; border-left: 3px solid #2ecc71;\">\n                        &lt;label for=\"directAudioUrl\">\u97f3\u9891\u6587\u4ef6URL:&lt;\/label>\n                        &lt;input type=\"url\" id=\"directAudioUrl\" placeholder=\"https:\/\/example.com\/your-audio-file.mp3\">\n                        &lt;small>\u8bf7\u8f93\u5165\u97f3\u9891\u6587\u4ef6\u7684\u516c\u7f51\u76f4\u94fe\u5730\u5740\uff08\u53ef\u76f4\u63a5\u4e0b\u8f7d\u7684URL\uff09&lt;\/small>\n                        &lt;button type=\"button\" id=\"validateUrlBtn\" style=\"margin-top: 8px; padding: 6px 12px; background: #3498db; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 12px;\">\ud83d\udd0d \u9a8c\u8bc1\u94fe\u63a5&lt;\/button>\n                        &lt;div id=\"urlValidationResult\" style=\"margin-top: 8px; display: none;\">&lt;\/div>\n                        &lt;div style=\"margin-top: 10px; padding: 8px; background: rgba(255, 255, 255, 0.7); border-radius: 5px;\">\n                            &lt;strong>\u2705 \u6709\u6548\u7684\u76f4\u94fe\u6765\u6e90\uff1a&lt;\/strong>&lt;br>\n                            1. &lt;strong>\u60a8\u81ea\u5df1\u7684\u7f51\u7ad9\u670d\u52a1\u5668&lt;\/strong>\uff1a\u5982 https:\/\/yoursite.com\/audio\/file.mp3&lt;br>\n                            2. &lt;strong>GitHub Raw\u94fe\u63a5&lt;\/strong>\uff1a\u4e0a\u4f20\u5230GitHub\u4ed3\u5e93\uff0c\u83b7\u53d6Raw\u6587\u4ef6\u94fe\u63a5&lt;br>\n                            3. &lt;strong>\u4e13\u4e1aCDN\u670d\u52a1&lt;\/strong>\uff1a\u5982\u963f\u91cc\u4e91OSS\u3001\u817e\u8baf\u4e91COS\u7b49\u7684\u516c\u5f00\u94fe\u63a5&lt;br>\n                            4. &lt;strong>\u514d\u8d39\u76f4\u94fe\u6258\u7ba1&lt;\/strong>\uff1a\u4f7f\u7528\u4e0b\u65b9\u7684\"\u901a\u8fc7\u4e0a\u4f20\u670d\u52a1\u83b7\u53d6URL\"&lt;br>\n                            &lt;br>\n                            &lt;strong style=\"color: #e74c3c;\">\u274c \u65e0\u6548\u94fe\u63a5\uff08\u4e0d\u662f\u76f4\u94fe\uff09\uff1a&lt;\/strong>&lt;br>\n                            \u2022 \u767e\u5ea6\u7f51\u76d8\u3001OneDrive\u7b49\u4e91\u76d8\u5206\u4eab\u94fe\u63a5&lt;br>\n                            \u2022 \u9700\u8981\u767b\u5f55\u6216\u9a8c\u8bc1\u7684\u94fe\u63a5&lt;br>\n                            \u2022 \u91cd\u5b9a\u5411\u94fe\u63a5&lt;br>\n                            &lt;br>\n                            &lt;small style=\"color: #666;\">&lt;strong>\u6d4b\u8bd5\u65b9\u6cd5\uff1a&lt;\/strong>\u76f4\u63a5\u5728\u6d4f\u89c8\u5668\u4e2d\u6253\u5f00URL\uff0c\u5e94\u8be5\u76f4\u63a5\u4e0b\u8f7d\/\u64ad\u653e\u97f3\u9891\u6587\u4ef6&lt;\/small>\n                        &lt;\/div>\n                    &lt;\/div>\n                &lt;\/div>\n                \n                &lt;!-- \u4e0a\u4f20\u670d\u52a1\u9009\u9879 -->\n                &lt;div id=\"uploadServiceConfig\" style=\"display: none;\">\n                    &lt;div class=\"input-group\" style=\"background: rgba(40, 167, 69, 0.1); padding: 15px; border-radius: 8px; border-left: 3px solid #28a745;\">\n                        &lt;label>\u2705 \u514d\u8d39\u76f4\u94fe\u6258\u7ba1\u670d\u52a1:&lt;\/label>\n                        &lt;p style=\"margin: 5px 0; color: #155724; font-size: 14px;\">\n                            &lt;strong>\u81ea\u52a8\u4e0a\u4f20\u5e76\u83b7\u53d6\u76f4\u94fe&lt;\/strong>&lt;br>\n                            \u2022 \u652f\u6301 catbox.moe\u3001file.io \u7b49\u670d\u52a1&lt;br>\n                            \u2022 \u81ea\u52a8\u751f\u6210\u53ef\u7528\u4e8e\u706b\u5c71\u5f15\u64ceAPI\u7684\u76f4\u94fe&lt;br>\n                            \u2022 \u5982\u679c\u9047\u5230\u7f51\u7edc\u95ee\u9898\uff0c\u8bf7\u5c1d\u8bd5\u51e0\u6b21\u6216\u4f7f\u7528\u81ea\u5b9a\u4e49\u670d\u52a1&lt;br>\n                        &lt;\/p>\n                    &lt;\/div>\n                    &lt;div class=\"input-group\">\n                        &lt;label for=\"customUploadUrl\">\u81ea\u5b9a\u4e49\u4e0a\u4f20\u670d\u52a1API (\u53ef\u9009):&lt;\/label>\n                        &lt;input type=\"text\" id=\"customUploadUrl\" placeholder=\"http:\/\/your-server.com\/upload\">\n                        &lt;small>\u5982\u679c\u60a8\u6709\u81ea\u5df1\u7684\u6587\u4ef6\u4e0a\u4f20API\uff0c\u8bf7\u586b\u5165\u3002API\u5e94\u8fd4\u56de JSON: {\"url\": \"\u76f4\u94fe\u5730\u5740\"}&lt;\/small>\n                    &lt;\/div>\n                &lt;\/div>\n                \n                &lt;div class=\"input-group\">\n                    &lt;label>\n                        &lt;input type=\"checkbox\" id=\"enableSpeakerDetection\" style=\"width: auto; margin-right: 10px;\" checked>\n                        \u542f\u7528\u8bf4\u8bdd\u4eba\u5206\u79bb\n                    &lt;\/label>\n                &lt;\/div>\n            &lt;\/div>\n        &lt;\/div>\n\n        &lt;!-- \u6587\u4ef6\u4e0a\u4f20\u533a\u57df -->\n        &lt;div class=\"file-upload\">\n            &lt;div id=\"fileUploadSection\">\n                &lt;label for=\"audioFile\">\ud83d\udcc1 \u9009\u62e9\u97f3\u9891\u6587\u4ef6&lt;\/label>\n                &lt;input type=\"file\" id=\"audioFile\" accept=\"audio\/*\">\n            &lt;\/div>\n            \n            &lt;div id=\"directUrlSection\" style=\"display: none;\">\n                &lt;div style=\"text-align: center; padding: 20px; background: rgba(46, 204, 113, 0.1); border-radius: 15px; border: 2px dashed #2ecc71;\">\n                    &lt;p style=\"margin: 0; color: #27ae60; font-weight: bold;\">\ud83d\udd17 \u4f7f\u7528\u76f4\u63a5URL\u6a21\u5f0f&lt;\/p>\n                    &lt;p style=\"margin: 5px 0 0 0; color: #666; font-size: 14px;\">\u8bf7\u5728\u4e0a\u65b9\u706b\u5c71\u5f15\u64ce\u914d\u7f6e\u4e2d\u8f93\u5165\u97f3\u9891\u6587\u4ef6URL&lt;\/p>\n                &lt;\/div>\n            &lt;\/div>\n        &lt;\/div>\n\n        &lt;!-- \u5f00\u59cb\u8f6c\u6362\u533a\u57df -->\n        &lt;div class=\"record-section\">\n            &lt;button id=\"convertBtn\" class=\"record-btn\" style=\"display: none; background: linear-gradient(45deg, #28a745, #20c997);\">\ud83d\ude80 \u5f00\u59cb\u8f6c\u6362&lt;\/button>\n        &lt;\/div>\n\n        &lt;!-- \u72b6\u6001\u663e\u793a -->\n        &lt;div id=\"status\" class=\"status\" style=\"display: none;\">&lt;\/div>\n\n        &lt;!-- \u97f3\u9891\u64ad\u653e\u5668 -->\n        &lt;audio id=\"audioPlayer\" class=\"audio-player\" controls style=\"display: none;\">&lt;\/audio>\n\n        &lt;!-- \u7ed3\u679c\u663e\u793a\u533a\u57df -->\n        &lt;div class=\"result-section\">\n            &lt;div style=\"display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;\">\n                &lt;h3>\ud83d\udcdd \u8f6c\u6362\u7ed3\u679c:&lt;\/h3>\n                &lt;button id=\"exportBtn\" class=\"toggle-btn\" style=\"display: none; background: #28a745;\">\ud83d\udcc4 \u5bfc\u51faTXT&lt;\/button>\n            &lt;\/div>\n            \n            &lt;!-- \u8f6c\u6362\u7ed3\u679c\u6587\u672c -->\n            &lt;div id=\"resultText\" class=\"result-text\">\u5728\u8fd9\u91cc\u5c06\u663e\u793a\u8bed\u97f3\u8f6c\u6587\u5b57\u7684\u7ed3\u679c...&lt;\/div>\n            \n            &lt;!-- \u97f3\u9891\u5206\u6790\u4fe1\u606f -->\n            &lt;div id=\"audioAnalysis\" class=\"analysis-section\" style=\"display: none;\">\n                &lt;h4>\ud83d\udd0d \u97f3\u9891\u5206\u6790:&lt;\/h4>\n                &lt;div id=\"analysisInfo\">&lt;\/div>\n            &lt;\/div>\n        &lt;\/div>\n    &lt;\/div>\n\n    &lt;script>\n        let currentAudioBlob;\n        let currentTranscription = ''; \/\/ \u4fdd\u5b58\u5f53\u524d\u8f6c\u6362\u7ed3\u679c\n        let currentSpeakerSegments = &#91;]; \/\/ \u4fdd\u5b58\u5f53\u524d\u8bf4\u8bdd\u4eba\u5206\u79bb\u7ed3\u679c\n\n        const convertBtn = document.getElementById('convertBtn');\n        const exportBtn = document.getElementById('exportBtn');\n        const status = document.getElementById('status');\n        const resultText = document.getElementById('resultText');\n        const audioPlayer = document.getElementById('audioPlayer');\n        const audioFileInput = document.getElementById('audioFile');\n        const audioAnalysis = document.getElementById('audioAnalysis');\n        const analysisInfo = document.getElementById('analysisInfo');\n        const apiProvider = document.getElementById('apiProvider');\n        const siliconflowConfig = document.getElementById('siliconflowConfig');\n        const volcengineConfig = document.getElementById('volcengineConfig');\n        const audioUrlMethod = document.getElementById('audioUrlMethod');\n        const directUrlConfig = document.getElementById('directUrlConfig');\n        const uploadServiceConfig = document.getElementById('uploadServiceConfig');\n        const directAudioUrlInput = document.getElementById('directAudioUrl');\n        const customUploadUrlInput = document.getElementById('customUploadUrl');\n        const fileUploadSection = document.getElementById('fileUploadSection');\n        const directUrlSection = document.getElementById('directUrlSection');\n        const validateUrlBtn = document.getElementById('validateUrlBtn');\n        const urlValidationResult = document.getElementById('urlValidationResult');\n\n        \/\/ API\u63d0\u4f9b\u5546\u5207\u6362\n        function switchApiProvider() {\n            const provider = apiProvider.value;\n            if (provider === 'siliconflow') {\n                siliconflowConfig.style.display = 'block';\n                volcengineConfig.style.display = 'none';\n                \/\/ \u7845\u57fa\u6d41\u52a8\u53ea\u652f\u6301\u6587\u4ef6\u4e0a\u4f20\n                fileUploadSection.style.display = 'block';\n                directUrlSection.style.display = 'none';\n                \/\/ \u91cd\u7f6e\u706b\u5c71\u5f15\u64ce\u914d\u7f6e\n                directUrlConfig.style.display = 'none';\n                uploadServiceConfig.style.display = 'none';\n                customUploadUrlInput.value = '';\n                directAudioUrlInput.value = '';\n                audioUrlMethod.value = 'direct';\n            } else if (provider === 'volcengine') {\n                siliconflowConfig.style.display = 'none';\n                volcengineConfig.style.display = 'block';\n                \/\/ \u91cd\u7f6e\u7845\u6d41\u914d\u7f6e\n                document.getElementById('apiUrl').value = 'https:\/\/api.siliconflow.cn\/v1\/audio\/transcriptions';\n                document.getElementById('apiKey').value = '';\n                document.getElementById('model').value = 'FunAudioLLM\/SenseVoiceSmall';\n\n                \/\/ \u6839\u636e\u97f3\u9891URL\u83b7\u53d6\u65b9\u5f0f\u663e\u793a\u914d\u7f6e\n                switchAudioUrlMethod();\n            }\n            \n            \/\/ \u91cd\u7f6e\u7ed3\u679c\u663e\u793a\n            resetResults();\n            \/\/ \u91cd\u7f6e\u8f6c\u6362\u6309\u94ae\u72b6\u6001\n            updateConvertButtonState();\n        }\n\n        \/\/ \u97f3\u9891URL\u83b7\u53d6\u65b9\u5f0f\u5207\u6362\n        function switchAudioUrlMethod() {\n            if (apiProvider.value !== 'volcengine') return;\n            \n            if (audioUrlMethod.value === 'direct') {\n                directUrlConfig.style.display = 'block';\n                uploadServiceConfig.style.display = 'none';\n                fileUploadSection.style.display = 'none';\n                directUrlSection.style.display = 'block';\n                customUploadUrlInput.value = '';\n            } else {\n                directUrlConfig.style.display = 'none';\n                uploadServiceConfig.style.display = 'block';\n                fileUploadSection.style.display = 'block';\n                directUrlSection.style.display = 'none';\n                directAudioUrlInput.value = '';\n            }\n            updateConvertButtonState();\n        }\n\n        \/\/ \u66f4\u65b0\u8f6c\u6362\u6309\u94ae\u72b6\u6001\n        function updateConvertButtonState() {\n            const provider = apiProvider.value;\n            let canConvert = false;\n            \n            if (provider === 'siliconflow') {\n                \/\/ \u7845\u57fa\u6d41\u52a8\u9700\u8981\u6587\u4ef6\n                canConvert = currentAudioBlob !== null;\n            } else if (provider === 'volcengine') {\n                if (audioUrlMethod.value === 'direct') {\n                    \/\/ \u76f4\u63a5URL\u6a21\u5f0f\uff0c\u68c0\u67e5URL\u662f\u5426\u5df2\u586b\u5199\n                    const url = directAudioUrlInput.value.trim();\n                    canConvert = url &amp;&amp; (url.startsWith('http:\/\/') || url.startsWith('https:\/\/'));\n                } else {\n                    \/\/ \u4e0a\u4f20\u670d\u52a1\u6a21\u5f0f\uff0c\u9700\u8981\u6587\u4ef6\n                    canConvert = currentAudioBlob !== null;\n                }\n            }\n            \n            if (canConvert) {\n                convertBtn.style.display = 'inline-block';\n                if (provider === 'volcengine' &amp;&amp; audioUrlMethod.value === 'direct') {\n                    showStatus(`\ud83d\udd17 \u5df2\u914d\u7f6e\u76f4\u63a5URL\uff0c\u70b9\u51fb\"\u5f00\u59cb\u8f6c\u6362\"\u8fdb\u884c\u8bed\u97f3\u8bc6\u522b`, 'success');\n                }\n            } else {\n                convertBtn.style.display = 'none';\n            }\n        }\n\n        \/\/ \u91cd\u7f6e\u7ed3\u679c\u663e\u793a\n        function resetResults() {\n            \/\/ speakerResults.style.display = 'none'; \/\/ \u79fb\u9664\u8bf4\u8bdd\u4eba\u7ed3\u679c\u663e\u793a\n            \/\/ originalResults.style.display = 'block'; \/\/ \u79fb\u9664\u5b8c\u6574\u6587\u672c\u663e\u793a\n            audioAnalysis.style.display = 'none';\n            \/\/ toggleView.style.display = 'none'; \/\/ \u79fb\u9664\u89c6\u56fe\u5207\u6362\u6309\u94ae\n            exportBtn.style.display = 'none';\n            \/\/ currentViewMode = 'original'; \/\/ \u79fb\u9664\u89c6\u56fe\u6a21\u5f0f\u53d8\u91cf\n            currentTranscription = '';\n            currentSpeakerSegments = &#91;];\n            resultText.textContent = '\u5728\u8fd9\u91cc\u5c06\u663e\u793a\u8bed\u97f3\u8f6c\u6587\u5b57\u7684\u7ed3\u679c...';\n        }\n\n        \/\/ \u663e\u793a\u72b6\u6001\u6d88\u606f\n        function showStatus(message, type = 'info') {\n            status.textContent = message;\n            status.className = `status ${type}`;\n            status.style.display = 'block';\n            console.log(`&#91;${type.toUpperCase()}] ${message}`); \/\/ \u6dfb\u52a0\u63a7\u5236\u53f0\u65e5\u5fd7\n        }\n\n        \/\/ \u9690\u85cf\u72b6\u6001\u6d88\u606f\n        function hideStatus() {\n            status.style.display = 'none';\n        }\n\n        \/\/ \u5bfc\u51fa\u4e3aTXT\u6587\u4ef6\n        function exportToTxt() {\n            let content = '';\n            const filename = `\u8bed\u97f3\u8f6c\u6587\u5b57_${new Date().toISOString().slice(0, 19).replace(\/:\/g, '-')}.txt`;\n            \n            if (currentSpeakerSegments.length > 0) {\n                \/\/ \u6709\u8bf4\u8bdd\u4eba\u5206\u79bb\u7ed3\u679c\uff0c\u5bfc\u51fa\u5206\u79bb\u7ed3\u679c+\u5b8c\u6574\u6587\u672c\n                content = '=== \u8bf4\u8bdd\u4eba\u5206\u79bb\u7ed3\u679c ===\\n\\n';\n                currentSpeakerSegments.forEach((segment) => {\n                    content += `&#91;\u8bf4\u8bdd\u4eba ${segment.speaker}] (${formatTime(segment.startTime)} - ${formatTime(segment.endTime)})\\n`;\n                    content += `${segment.text}\\n\\n`;\n                });\n                content += `\\n=== \u5b8c\u6574\u6587\u672c ===\\n\\n${currentTranscription}`;\n            } else {\n                \/\/ \u6ca1\u6709\u8bf4\u8bdd\u4eba\u5206\u79bb\u7ed3\u679c\uff0c\u5bfc\u51fa\u5b8c\u6574\u6587\u672c\n                content = currentTranscription;\n            }\n            \n            if (!content.trim()) {\n                showStatus('\u26a0\ufe0f \u6ca1\u6709\u53ef\u5bfc\u51fa\u7684\u5185\u5bb9', 'error');\n                return;\n            }\n            \n            \/\/ \u521b\u5efa\u4e0b\u8f7d\u94fe\u63a5\n            const blob = new Blob(&#91;content], { type: 'text\/plain;charset=utf-8' });\n            const url = URL.createObjectURL(blob);\n            const a = document.createElement('a');\n            a.href = url;\n            a.download = filename;\n            document.body.appendChild(a);\n            a.click();\n            document.body.removeChild(a);\n            URL.revokeObjectURL(url);\n            \n            showStatus('\ud83d\udcc4 \u6587\u4ef6\u5df2\u5bfc\u51fa\uff01', 'success');\n        }\n\n        \/\/ \u4e0a\u4f20\u6587\u4ef6\u5230\u6258\u7ba1\u670d\u52a1\uff08\u6539\u8fdb\u7248\uff09\n        async function uploadToCatbox(file) {\n            showStatus('\ud83d\udce4 \u6b63\u5728\u5c1d\u8bd5\u514d\u8d39\u6258\u7ba1\u670d\u52a1...', 'info');\n            \n            \/\/ \u53ef\u7528\u7684\u6258\u7ba1\u670d\u52a1\u5217\u8868\n            const uploadServices = &#91;\n                {\n                    name: 'catbox.moe',\n                    upload: async (file) => {\n                        const formData = new FormData();\n                        formData.append('reqtype', 'fileupload');\n                        formData.append('fileToUpload', file);\n                        \n                        const response = await fetch('https:\/\/catbox.moe\/user\/api.php', {\n                            method: 'POST',\n                            body: formData\n                        });\n                        \n                        if (response.ok) {\n                            const result = await response.text();\n                            if (result.startsWith('https:\/\/files.catbox.moe\/')) {\n                                return result.trim();\n                            }\n                        }\n                        throw new Error('catbox.moe \u4e0a\u4f20\u5931\u8d25');\n                    }\n                },\n                {\n                    name: 'file.io',\n                    upload: async (file) => {\n                        const formData = new FormData();\n                        formData.append('file', file);\n                        \n                        const response = await fetch('https:\/\/file.io', {\n                            method: 'POST',\n                            body: formData\n                        });\n                        \n                        if (response.ok) {\n                            const result = await response.json();\n                            if (result.success &amp;&amp; result.link) {\n                                return result.link;\n                            }\n                        }\n                        throw new Error('file.io \u4e0a\u4f20\u5931\u8d25');\n                    }\n                }\n            ];\n            \n            let lastError = null;\n            \n            \/\/ \u5c1d\u8bd5\u5404\u4e2a\u670d\u52a1\n            for (let i = 0; i &lt; uploadServices.length; i++) {\n                const service = uploadServices&#91;i];\n                try {\n                    showStatus(`\ud83d\udce4 \u6b63\u5728\u5c1d\u8bd5 ${service.name}... (${i + 1}\/${uploadServices.length})`, 'info');\n                    console.log(`\u5c1d\u8bd5\u4e0a\u4f20\u5230: ${service.name}`);\n                    \n                    const url = await service.upload(file);\n                    console.log(`${service.name} \u4e0a\u4f20\u6210\u529f:`, url);\n                    \n                    showStatus(`\u2705 \u6587\u4ef6\u4e0a\u4f20\u6210\u529f\uff01\u4f7f\u7528\u670d\u52a1: ${service.name}`, 'success');\n                    return url;\n                    \n                } catch (error) {\n                    console.warn(`${service.name} \u4e0a\u4f20\u5931\u8d25:`, error.message);\n                    lastError = error;\n                    \n                    if (i &lt; uploadServices.length - 1) {\n                        showStatus(`\u26a0\ufe0f ${service.name} \u5931\u8d25\uff0c\u5c1d\u8bd5\u4e0b\u4e00\u4e2a\u670d\u52a1...`, 'info');\n                        await new Promise(resolve => setTimeout(resolve, 1000));\n                    }\n                }\n            }\n            \n            \/\/ \u6240\u6709\u670d\u52a1\u90fd\u5931\u8d25\u4e86\n            console.error('\u6240\u6709\u514d\u8d39\u6258\u7ba1\u670d\u52a1\u90fd\u5931\u8d25\u4e86');\n            showStatus(`\u274c \u514d\u8d39\u6258\u7ba1\u670d\u52a1\u6682\u65f6\u4e0d\u53ef\u7528`, 'error');\n            \n            \/\/ \u63d0\u4f9b\u8be6\u7ec6\u7684\u89e3\u51b3\u65b9\u6848\n            const errorMessage = `\n\u514d\u8d39\u6258\u7ba1\u670d\u52a1\u6682\u65f6\u4e0d\u53ef\u7528\uff0c\u8bf7\u5c1d\u8bd5\u4ee5\u4e0b\u65b9\u6848\uff1a\n\n\u2705 \u63a8\u8350\u65b9\u6848\uff1a\n1. \u4f7f\u7528\u60a8\u81ea\u5df1\u7684\u670d\u52a1\u5668\u4e0a\u4f20\u97f3\u9891\u6587\u4ef6\n2. \u4e0a\u4f20\u5230GitHub\u4ed3\u5e93\uff0c\u83b7\u53d6Raw\u94fe\u63a5\n3. \u4f7f\u7528\u4e13\u4e1aCDN\u670d\u52a1\uff08\u963f\u91cc\u4e91OSS\u3001\u817e\u8baf\u4e91COS\u7b49\uff09\n\n\ud83d\udd27 GitHub\u76f4\u94fe\u6559\u7a0b\uff1a\n1. \u767b\u5f55GitHub\uff0c\u521b\u5efa\u65b0\u4ed3\u5e93\n2. \u4e0a\u4f20\u97f3\u9891\u6587\u4ef6\u5230\u4ed3\u5e93\n3. \u70b9\u51fb\u6587\u4ef6 \u2192 Raw \u6309\u94ae\n4. \u590d\u5236Raw\u94fe\u63a5\u5730\u5740\n\n\ud83d\udca1 \u81ea\u5b9a\u4e49\u4e0a\u4f20\u670d\u52a1\uff1a\n\u5982\u679c\u60a8\u6709\u81ea\u5df1\u7684\u6587\u4ef6\u4e0a\u4f20API\uff0c\u8bf7\u5728\u4e0a\u65b9\u586b\u5199\u81ea\u5b9a\u4e49\u4e0a\u4f20\u670d\u52a1\u5730\u5740\n`;\n            \n            throw new Error(errorMessage);\n        }\n\n        \/\/ \u751f\u6210UUID\n        function generateUUID() {\n            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(\/&#91;xy]\/g, function(c) {\n                const r = Math.random() * 16 | 0;\n                const v = c == 'x' ? r : (r &amp; 0x3 | 0x8);\n                return v.toString(16);\n            });\n        }\n\n        \/\/ \u521b\u5efa\u97f3\u9891URL\n        async function createAudioUrl(audioBlob) {\n            const customUploadUrl = customUploadUrlInput.value.trim();\n            \n            \/\/ \u5982\u679c\u7528\u6237\u63d0\u4f9b\u4e86\u81ea\u5b9a\u4e49\u4e0a\u4f20\u670d\u52a1\uff0c\u4f18\u5148\u4f7f\u7528\n            if (customUploadUrl) {\n                try {\n                    showStatus('\ud83d\udce4 \u6b63\u5728\u4f7f\u7528\u81ea\u5b9a\u4e49\u4e0a\u4f20\u670d\u52a1...', 'info');\n                    console.log('\u5c1d\u8bd5\u81ea\u5b9a\u4e49\u4e0a\u4f20\u670d\u52a1:', customUploadUrl);\n                    \n                    const formData = new FormData();\n                    formData.append('file', audioBlob);\n                    formData.append('audio', audioBlob); \/\/ \u517c\u5bb9\u4e0d\u540c\u7684\u5b57\u6bb5\u540d\n                    \n                    const response = await fetch(customUploadUrl, {\n                        method: 'POST',\n                        body: formData\n                    });\n                    \n                    if (!response.ok) {\n                        throw new Error(`\u81ea\u5b9a\u4e49\u670d\u52a1\u54cd\u5e94\u5931\u8d25: ${response.status}`);\n                    }\n                    \n                    const result = await response.json();\n                    const url = result.url || result.file_url || result.link;\n                    \n                    if (url) {\n                        console.log('\u81ea\u5b9a\u4e49\u670d\u52a1\u4e0a\u4f20\u6210\u529f:', url);\n                        showStatus('\u2705 \u81ea\u5b9a\u4e49\u670d\u52a1\u4e0a\u4f20\u6210\u529f\uff01', 'success');\n                        return url;\n                    } else {\n                        throw new Error('\u81ea\u5b9a\u4e49\u670d\u52a1\u8fd4\u56de\u6570\u636e\u683c\u5f0f\u4e0d\u6b63\u786e');\n                    }\n                    \n                } catch (error) {\n                    console.warn('\u81ea\u5b9a\u4e49\u4e0a\u4f20\u670d\u52a1\u5931\u8d25\uff0c\u8f6c\u7528\u514d\u8d39\u670d\u52a1:', error.message);\n                    showStatus('\u26a0\ufe0f \u81ea\u5b9a\u4e49\u670d\u52a1\u5931\u8d25\uff0c\u8f6c\u7528\u514d\u8d39\u6258\u7ba1\u670d\u52a1...', 'info');\n                }\n            }\n            \n            \/\/ \u4f7f\u7528\u514d\u8d39\u6258\u7ba1\u670d\u52a1\n            return await uploadToCatbox(audioBlob);\n        }\n\n        \/\/ \u5c06\u97f3\u9891\u8f6c\u6362\u4e3a\u6587\u5b57\n        async function convertToText() {\n            const provider = apiProvider.value;\n            \n            \/\/ \u68c0\u67e5\u662f\u5426\u9700\u8981\u6587\u4ef6\n            if (provider === 'siliconflow' || (provider === 'volcengine' &amp;&amp; audioUrlMethod.value === 'upload')) {\n                if (!currentAudioBlob) {\n                    showStatus('\u26a0\ufe0f \u8bf7\u5148\u9009\u62e9\u97f3\u9891\u6587\u4ef6', 'error');\n                    return;\n                }\n            }\n\n            console.log('\u5f00\u59cb\u8f6c\u6362\uff0c\u63d0\u4f9b\u5546:', provider, '\u6587\u4ef6\u5927\u5c0f:', currentAudioBlob ? currentAudioBlob.size : '\u4f7f\u7528URL');\n            \n            try {\n                if (provider === 'siliconflow') {\n                    await convertWithSiliconFlow(currentAudioBlob);\n                } else if (provider === 'volcengine') {\n                    await convertWithVolcEngine(currentAudioBlob);\n                }\n            } catch (error) {\n                console.error('\u8f6c\u6362\u5931\u8d25:', error);\n                showStatus(`\u274c \u8f6c\u6362\u5931\u8d25: ${error.message}`, 'error');\n                displayErrorInfo(provider, error);\n            }\n        }\n\n        \/\/ SiliconFlow\u8f6c\u6362\uff08\u7eaf\u8f6c\u5199\uff09\n        async function convertWithSiliconFlow(audioBlob) {\n            const apiUrl = document.getElementById('apiUrl').value.trim();\n            const apiKey = document.getElementById('apiKey').value.trim();\n            const model = document.getElementById('model').value.trim();\n\n            if (!apiKey) {\n                throw new Error('\u8bf7\u586b\u5165SiliconFlow\u7684API\u5bc6\u94a5');\n            }\n\n            showStatus('\ud83d\udd04 \u6b63\u5728\u8f6c\u6362\u4e3a\u6587\u5b57...', 'info');\n            \n            const formData = new FormData();\n            formData.append('file', audioBlob, 'recording.webm');\n            formData.append('model', model);\n\n            console.log('\u53d1\u9001SiliconFlow\u8bf7\u6c42:', { apiUrl, model, fileSize: audioBlob.size });\n\n            const response = await fetch(apiUrl, {\n                method: 'POST',\n                headers: { 'Authorization': `Bearer ${apiKey}` },\n                body: formData\n            });\n\n            console.log('SiliconFlow\u54cd\u5e94\u72b6\u6001:', response.status);\n\n            if (!response.ok) {\n                let errorMessage = `API\u8bf7\u6c42\u5931\u8d25: ${response.status} ${response.statusText}`;\n                try {\n                    const errorData = await response.json();\n                    console.log('SiliconFlow\u9519\u8bef\u54cd\u5e94:', errorData);\n                    if (errorData.error &amp;&amp; errorData.error.message) {\n                        errorMessage += ` - ${errorData.error.message}`;\n                    }\n                } catch (e) {\n                    console.log('\u65e0\u6cd5\u89e3\u6790\u9519\u8bef\u54cd\u5e94');\n                }\n                throw new Error(errorMessage);\n            }\n\n            const result = await response.json();\n            console.log('SiliconFlow\u6210\u529f\u54cd\u5e94:', result);\n            \n            const transcription = result.text;\n\n            if (!transcription) {\n                throw new Error('\u8f6c\u6362\u7ed3\u679c\u4e3a\u7a7a');\n            }\n\n            \/\/ \u5148\u91cd\u7f6e\u754c\u9762\n            resetResults();\n            \n            \/\/ \u518d\u4fdd\u5b58\u548c\u663e\u793a\u7ed3\u679c\n            currentTranscription = transcription;\n            currentSpeakerSegments = &#91;];\n            resultText.textContent = transcription;\n            \n            \/\/ \u542f\u7528\u5bfc\u51fa\u6309\u94ae\n            exportBtn.style.display = 'inline-block';\n            \n            showStatus('\u2705 \u8f6c\u6362\u5b8c\u6210\uff01', 'success');\n            console.log('SiliconFlow\u8f6c\u6362\u5b8c\u6210\uff0c\u7ed3\u679c\u957f\u5ea6:', transcription.length);\n            console.log('\u4fdd\u5b58\u7684\u7ed3\u679c:', currentTranscription.substring(0, 100) + '...');\n        }\n\n        \/\/ \u706b\u5c71\u5f15\u64ce\u63d0\u4ea4\u4efb\u52a1\n        async function submitVolcEngineTask(audioUrl) {\n            const appKey = document.getElementById('volcAppKey').value.trim();\n            const accessKey = document.getElementById('volcAccessKey').value.trim();\n            const enableSpeakerDetection = document.getElementById('enableSpeakerDetection').checked;\n            \n            if (!appKey || !accessKey) {\n                throw new Error('\u8bf7\u586b\u5165\u706b\u5c71\u5f15\u64ce\u7684APP ID\u548cAccess Token');\n            }\n            \n            const taskId = generateUUID();\n            \n            const requestBody = {\n                user: {\n                    uid: \"web-user-\" + Date.now()\n                },\n                audio: {\n                    format: \"mp3\",\n                    url: audioUrl\n                },\n                request: {\n                    model_name: \"bigmodel\",\n                    enable_itn: true,\n                    enable_punc: true,\n                    enable_speaker_info: enableSpeakerDetection,\n                    show_utterances: true\n                }\n            };\n            \n            console.log('\u63d0\u4ea4\u7684\u8bf7\u6c42\u53c2\u6570:', JSON.stringify(requestBody, null, 2)); \/\/ \u6dfb\u52a0\u8bf7\u6c42\u53c2\u6570\u65e5\u5fd7\n            console.log('\u8bf4\u8bdd\u4eba\u5206\u79bb\u662f\u5426\u542f\u7528:', enableSpeakerDetection); \/\/ \u660e\u786e\u663e\u793a\u53c2\u6570\u72b6\u6001\n            \n            const response = await fetch('https:\/\/openspeech.bytedance.com\/api\/v3\/auc\/bigmodel\/submit', {\n                method: 'POST',\n                headers: {\n                    'Content-Type': 'application\/json',\n                    'X-Api-App-Key': appKey,\n                    'X-Api-Access-Key': accessKey,\n                    'X-Api-Resource-Id': 'volc.bigasr.auc',\n                    'X-Api-Request-Id': taskId,\n                    'X-Api-Sequence': '-1'\n                },\n                body: JSON.stringify(requestBody)\n            });\n            \n            console.log('\u63d0\u4ea4\u4efb\u52a1\u54cd\u5e94\u72b6\u6001:', response.status); \/\/ \u6dfb\u52a0\u54cd\u5e94\u72b6\u6001\u65e5\u5fd7\n            console.log('\u63d0\u4ea4\u4efb\u52a1\u54cd\u5e94\u5934:', Object.fromEntries(response.headers.entries())); \/\/ \u6dfb\u52a0\u54cd\u5e94\u5934\u65e5\u5fd7\n            \n            if (!response.ok) {\n                const statusCode = response.headers.get('X-Api-Status-Code');\n                const message = response.headers.get('X-Api-Message');\n                throw new Error(`\u4efb\u52a1\u63d0\u4ea4\u5931\u8d25: ${statusCode} - ${message}`);\n            }\n            \n            return taskId;\n        }\n\n        \/\/ \u706b\u5c71\u5f15\u64ce\u67e5\u8be2\u7ed3\u679c\n        async function queryVolcEngineResult(taskId) {\n            const appKey = document.getElementById('volcAppKey').value.trim();\n            const accessKey = document.getElementById('volcAccessKey').value.trim();\n            \n            console.log('\u67e5\u8be2\u4efb\u52a1ID:', taskId); \/\/ \u6dfb\u52a0\u4efb\u52a1ID\u65e5\u5fd7\n            \n            const response = await fetch('https:\/\/openspeech.bytedance.com\/api\/v3\/auc\/bigmodel\/query', {\n                method: 'POST',\n                headers: {\n                    'Content-Type': 'application\/json',\n                    'X-Api-App-Key': appKey,\n                    'X-Api-Access-Key': accessKey,\n                    'X-Api-Resource-Id': 'volc.bigasr.auc',\n                    'X-Api-Request-Id': taskId,\n                    'X-Api-Sequence': '-1'\n                },\n                body: '{}'\n            });\n            \n            const statusCode = response.headers.get('X-Api-Status-Code');\n            console.log('\u67e5\u8be2\u54cd\u5e94\u72b6\u6001\u7801:', statusCode); \/\/ \u6dfb\u52a0\u72b6\u6001\u7801\u65e5\u5fd7\n            console.log('\u67e5\u8be2\u54cd\u5e94\u5934:', Object.fromEntries(response.headers.entries())); \/\/ \u6dfb\u52a0\u54cd\u5e94\u5934\u65e5\u5fd7\n            \n            if (statusCode === '20000000') {\n                \/\/ \u6210\u529f\n                const result = await response.json();\n                console.log('\u67e5\u8be2\u6210\u529f\uff0c\u5b8c\u6574\u8fd4\u56de\u7ed3\u679c:', JSON.stringify(result, null, 2)); \/\/ \u6dfb\u52a0\u5b8c\u6574\u7ed3\u679c\u65e5\u5fd7\n                return { status: 'completed', data: result };\n            } else if (statusCode === '40000001') {\n                \/\/ \u5904\u7406\u4e2d\n                console.log('\u4efb\u52a1\u4ecd\u5728\u5904\u7406\u4e2d...'); \/\/ \u6dfb\u52a0\u5904\u7406\u4e2d\u65e5\u5fd7\n                return { status: 'processing' };\n            } else {\n                \/\/ \u5931\u8d25\n                const message = response.headers.get('X-Api-Message');\n                console.error('\u67e5\u8be2\u5931\u8d25:', statusCode, message); \/\/ \u6dfb\u52a0\u5931\u8d25\u65e5\u5fd7\n                throw new Error(`\u67e5\u8be2\u5931\u8d25: ${statusCode} - ${message}`);\n            }\n        }\n\n        \/\/ \u706b\u5c71\u5f15\u64ce\u8f6e\u8be2\u7ed3\u679c\n        async function pollVolcEngineResult(taskId, maxAttempts = 30) {\n            for (let i = 0; i &lt; maxAttempts; i++) {\n                try {\n                    const result = await queryVolcEngineResult(taskId);\n                    \n                    if (result.status === 'completed') {\n                        return result.data;\n                    } else if (result.status === 'processing') {\n                        showStatus(`\ud83d\udd04 \u5904\u7406\u4e2d... (${i + 1}\/${maxAttempts})`, 'info');\n                        await new Promise(resolve => setTimeout(resolve, 2000)); \/\/ \u7b49\u5f852\u79d2\n                        continue;\n                    }\n                } catch (error) {\n                    if (i === maxAttempts - 1) throw error;\n                    await new Promise(resolve => setTimeout(resolve, 2000));\n                }\n            }\n            \n            throw new Error('\u5904\u7406\u8d85\u65f6\uff0c\u8bf7\u7a0d\u540e\u91cd\u8bd5');\n        }\n\n        \/\/ \u706b\u5c71\u5f15\u64ce\u8f6c\u6362\n        async function convertWithVolcEngine(audioBlob) {\n            showStatus('\ud83d\udd04 \u51c6\u5907\u8fdb\u884c\u8bed\u97f3\u8bc6\u522b...', 'info');\n            \n            \/\/ \u83b7\u53d6\u97f3\u9891URL\n            let audioUrl;\n            if (audioUrlMethod.value === 'direct') {\n                audioUrl = directAudioUrlInput.value.trim();\n                if (!audioUrl) {\n                    throw new Error('\u8bf7\u5148\u8f93\u5165\u97f3\u9891\u6587\u4ef6URL');\n                }\n                if (!audioUrl.startsWith('http:\/\/') &amp;&amp; !audioUrl.startsWith('https:\/\/')) {\n                    throw new Error('\u97f3\u9891URL\u5fc5\u987b\u4ee5 http:\/\/ \u6216 https:\/\/ \u5f00\u5934');\n                }\n                showStatus(`\ud83d\udcc1 \u4f7f\u7528\u76f4\u63a5URL: ${audioUrl}`, 'info');\n                console.log('\u4f7f\u7528\u76f4\u63a5URL:', audioUrl);\n            } else {\n                showStatus('\ud83d\udd04 \u6b63\u5728\u4e0a\u4f20\u97f3\u9891\u6587\u4ef6...', 'info');\n                audioUrl = await createAudioUrl(audioBlob);\n                console.log('\u97f3\u9891\u4e0a\u4f20\u5b8c\u6210\uff0cURL:', audioUrl);\n            }\n            \n            showStatus('\ud83d\udd04 \u6b63\u5728\u63d0\u4ea4\u8bc6\u522b\u4efb\u52a1...', 'info');\n            \n            \/\/ \u63d0\u4ea4\u4efb\u52a1\n            const taskId = await submitVolcEngineTask(audioUrl);\n            console.log('\u4efb\u52a1\u63d0\u4ea4\u6210\u529f\uff0cID:', taskId);\n            \n            showStatus('\ud83d\udd04 \u6b63\u5728\u5904\u7406\u97f3\u9891\uff0c\u8bf7\u7a0d\u5019...', 'info');\n            \n            \/\/ \u8f6e\u8be2\u7ed3\u679c\n            const volcResult = await pollVolcEngineResult(taskId);\n            console.log('\u706b\u5c71\u5f15\u64ce\u5904\u7406\u5b8c\u6210:', volcResult);\n            \n            \/\/ \u89e3\u6790\u7ed3\u679c\n            const transcription = volcResult.result.text;\n            \n            if (!transcription) {\n                throw new Error('\u8f6c\u6362\u7ed3\u679c\u4e3a\u7a7a');\n            }\n\n            \/\/ \u5148\u91cd\u7f6e\u754c\u9762\n            resetResults();\n\n            \/\/ \u4fdd\u5b58\u57fa\u672c\u7ed3\u679c\n            currentTranscription = transcription;\n            currentSpeakerSegments = &#91;];\n\n            \/\/ \u663e\u793a\u57fa\u672c\u7ed3\u679c\n            resultText.textContent = transcription;\n            \n            \/\/ \u542f\u7528\u5bfc\u51fa\u6309\u94ae\n            exportBtn.style.display = 'inline-block';\n            \n            \/\/ \u68c0\u67e5\u662f\u5426\u542f\u7528\u4e86\u8bf4\u8bdd\u4eba\u5206\u79bb\u4e14\u6709\u7ed3\u679c\n            const enableSpeakerDetection = document.getElementById('enableSpeakerDetection').checked;\n            if (enableSpeakerDetection &amp;&amp; volcResult.result.utterances &amp;&amp; volcResult.result.utterances.length > 0) {\n                const speakerSegments = parseVolcEngineSpeakerResult(volcResult);\n                console.log('\u89e3\u6790\u7684\u8bf4\u8bdd\u4eba\u7247\u6bb5:', speakerSegments); \/\/ \u6dfb\u52a0\u8c03\u8bd5\u65e5\u5fd7\n                \n                if (speakerSegments.length > 0) {\n                    \/\/ \u4fdd\u5b58\u8bf4\u8bdd\u4eba\u5206\u79bb\u7ed3\u679c\n                    currentSpeakerSegments = speakerSegments;\n                    \n                    \/\/ \u751f\u6210\u5e26\u8bf4\u8bdd\u4eba\u6807\u8bb0\u7684\u6587\u672c\u683c\u5f0f\n                    let speakerText = '';\n                    speakerSegments.forEach((segment) => {\n                        speakerText += `&#91;\u8bf4\u8bdd\u4eba ${segment.speaker}] (${formatTime(segment.startTime)} - ${formatTime(segment.endTime)})\\n`;\n                        speakerText += `${segment.text}\\n\\n`;\n                    });\n                    \n                    \/\/ \u663e\u793a\u5e26\u8bf4\u8bdd\u4eba\u6807\u8bb0\u7684\u6587\u672c\n                    resultText.textContent = speakerText.trim();\n                    \n                    \/\/ \u663e\u793a\u5206\u6790\u4fe1\u606f\n                    if (volcResult.audio_info) {\n                        audioAnalysis.style.display = 'block';\n                        const urlMethod = audioUrlMethod.value === 'direct' ? '\u76f4\u63a5URL' : '\u514d\u8d39\u6258\u7ba1\u670d\u52a1';\n                        const speakerCount = Math.max(...speakerSegments.map(s => s.speaker));\n                        analysisInfo.innerHTML = `\n                            &lt;p>&lt;strong>\u97f3\u9891\u65f6\u957f:&lt;\/strong> ${(volcResult.audio_info.duration \/ 1000).toFixed(2)} \u79d2&lt;\/p>\n                            &lt;p>&lt;strong>\u68c0\u6d4b\u5230\u8bf4\u8bdd\u4eba\u6570\u91cf:&lt;\/strong> ${speakerCount} \u4eba&lt;\/p>\n                            &lt;p>&lt;strong>\u97f3\u9891\u7247\u6bb5\u6570\u91cf:&lt;\/strong> ${speakerSegments.length} \u4e2a&lt;\/p>\n                            &lt;p>&lt;strong>API\u63d0\u4f9b\u5546:&lt;\/strong> \u706b\u5c71\u5f15\u64ce (\u4e13\u4e1a\u7ea7)&lt;\/p>\n                            &lt;p>&lt;strong>\u97f3\u9891\u83b7\u53d6\u65b9\u5f0f:&lt;\/strong> ${urlMethod}&lt;\/p>\n                        `;\n                    }\n                    \n                    showStatus(`\u2705 \u8f6c\u6362\u5b8c\u6210\uff01\u5df2\u68c0\u6d4b\u5230 ${Math.max(...speakerSegments.map(s => s.speaker))} \u4e2a\u8bf4\u8bdd\u4eba`, 'success');\n                } else {\n                    \/\/ \u6ca1\u6709\u8bf4\u8bdd\u4eba\u5206\u79bb\u7ed3\u679c\uff0c\u663e\u793a\u5b8c\u6574\u6587\u672c\n                    resultText.textContent = transcription;\n                    showStatus('\u2705 \u8f6c\u6362\u5b8c\u6210\uff01\u672a\u68c0\u6d4b\u5230\u591a\u4e2a\u8bf4\u8bdd\u4eba', 'success');\n                }\n            } else {\n                \/\/ \u672a\u542f\u7528\u8bf4\u8bdd\u4eba\u5206\u79bb\u6216\u6ca1\u6709utterances\uff0c\u663e\u793a\u5b8c\u6574\u6587\u672c\n                resultText.textContent = transcription;\n                showStatus('\u2705 \u8f6c\u6362\u5b8c\u6210\uff01', 'success');\n            }\n            \n            console.log('\u706b\u5c71\u5f15\u64ce\u8f6c\u6362\u5b8c\u6210\uff0c\u7ed3\u679c\u957f\u5ea6:', transcription.length);\n            console.log('\u4fdd\u5b58\u7684\u7ed3\u679c:', currentTranscription.substring(0, 100) + '...');\n        }\n\n        \/\/ \u89e3\u6790\u706b\u5c71\u5f15\u64ce\u8bf4\u8bdd\u4eba\u7ed3\u679c\n        function parseVolcEngineSpeakerResult(volcResult) {\n            console.log('\u5b8c\u6574\u7684\u706b\u5c71\u5f15\u64ce\u8fd4\u56de\u7ed3\u679c:', volcResult); \/\/ \u6dfb\u52a0\u5b8c\u6574\u8c03\u8bd5\u65e5\u5fd7\n            \n            if (!volcResult.result || !volcResult.result.utterances) {\n                console.log('\u6ca1\u6709\u627e\u5230utterances\u6570\u636e');\n                return &#91;];\n            }\n            \n            const utterances = volcResult.result.utterances;\n            console.log('utterances\u6570\u636e:', utterances); \/\/ \u6dfb\u52a0utterances\u8c03\u8bd5\u65e5\u5fd7\n            console.log('utterances\u6570\u7ec4\u957f\u5ea6:', utterances.length);\n            const segments = &#91;];\n            \n            utterances.forEach((utterance, index) => {\n                console.log(`utterance ${index} \u5b8c\u6574\u7ed3\u6784:`, JSON.stringify(utterance, null, 2)); \/\/ \u6dfb\u52a0\u8be6\u7ec6\u7684utterance\u7ed3\u6784\u65e5\u5fd7\n                \n                \/\/ \u5c1d\u8bd5\u591a\u79cd\u53ef\u80fd\u7684\u8bf4\u8bdd\u4ebaID\u5b57\u6bb5\n                let speakerId = 1; \/\/ \u9ed8\u8ba4\u503c\n                \n                \/\/ \u6309\u4f18\u5148\u7ea7\u5c1d\u8bd5\u4e0d\u540c\u7684\u5b57\u6bb5\u540d\n                if (utterance.additions &amp;&amp; utterance.additions.speaker !== undefined) {\n                    speakerId = parseInt(utterance.additions.speaker); \/\/ \u706b\u5c71\u5f15\u64ce\u7684\u8bf4\u8bdd\u4ebaID\u5728additions.speaker\u4e2d\n                    console.log(`\u627e\u5230additions.speaker: ${speakerId}`);\n                } else if (utterance.speaker_id !== undefined) {\n                    speakerId = utterance.speaker_id;\n                    console.log(`\u627e\u5230speaker_id: ${speakerId}`);\n                } else if (utterance.spk_id !== undefined) {\n                    speakerId = utterance.spk_id;\n                    console.log(`\u627e\u5230spk_id: ${speakerId}`);\n                } else if (utterance.speaker !== undefined) {\n                    speakerId = utterance.speaker;\n                    console.log(`\u627e\u5230speaker: ${speakerId}`);\n                } else if (utterance.channel_id !== undefined) {\n                    speakerId = utterance.channel_id;\n                    console.log(`\u627e\u5230channel_id: ${speakerId}`);\n                } else if (utterance.spk !== undefined) {\n                    speakerId = utterance.spk;\n                    console.log(`\u627e\u5230spk: ${speakerId}`);\n                } else {\n                    console.log(`utterance ${index} \u6ca1\u6709\u627e\u5230\u8bf4\u8bdd\u4ebaID\u5b57\u6bb5\uff0c\u4f7f\u7528\u9ed8\u8ba4\u503c1`);\n                }\n                \n                segments.push({\n                    speaker: speakerId,\n                    startTime: utterance.start_time \/ 1000, \/\/ \u8f6c\u6362\u4e3a\u79d2\n                    endTime: utterance.end_time \/ 1000,\n                    text: utterance.text\n                });\n                \n                console.log(`\u89e3\u6790\u7ed3\u679c ${index}: speaker=${speakerId}, text=\"${utterance.text.substring(0, 20)}...\"`);\n            });\n            \n            console.log('\u89e3\u6790\u540e\u7684segments:', segments); \/\/ \u6dfb\u52a0\u89e3\u6790\u7ed3\u679c\u8c03\u8bd5\u65e5\u5fd7\n            \n            \/\/ \u7edf\u8ba1\u8bf4\u8bdd\u4eba\u6570\u91cf\n            const speakers = &#91;...new Set(segments.map(s => s.speaker))];\n            console.log('\u68c0\u6d4b\u5230\u7684\u8bf4\u8bdd\u4ebaID\u5217\u8868:', speakers);\n            console.log('\u8bf4\u8bdd\u4eba\u6570\u91cf:', speakers.length);\n            \n            return segments;\n        }\n\n        \/\/ \u663e\u793a\u706b\u5c71\u5f15\u64ce\u8bf4\u8bdd\u4eba\u7ed3\u679c\n        function displayVolcEngineSpeakerResults(segments) {\n            \/\/ \u8fd9\u4e2a\u51fd\u6570\u5df2\u7ecf\u4e0d\u518d\u9700\u8981\uff0c\u56e0\u4e3a\u6211\u4eec\u76f4\u63a5\u5728resultText\u4e2d\u663e\u793a\u5e26\u8bf4\u8bdd\u4eba\u6807\u8bb0\u7684\u6587\u672c\n            console.log('displayVolcEngineSpeakerResults\u51fd\u6570\u5df2\u5e9f\u5f03');\n        }\n\n        \/\/ \u683c\u5f0f\u5316\u65f6\u95f4\n        function formatTime(seconds) {\n            const mins = Math.floor(seconds \/ 60);\n            const secs = Math.floor(seconds % 60);\n            return `${mins}:${secs.toString().padStart(2, '0')}`;\n        }\n\n        \/\/ \u5207\u6362\u89c6\u56fe\uff08\u5df2\u5e9f\u5f03\uff09\n        function toggleViewMode() {\n            \/\/ \u8fd9\u4e2a\u51fd\u6570\u5df2\u7ecf\u4e0d\u518d\u9700\u8981\uff0c\u56e0\u4e3a\u6211\u4eec\u79fb\u9664\u4e86\u89c6\u56fe\u5207\u6362\u529f\u80fd\n            console.log('toggleViewMode\u51fd\u6570\u5df2\u5e9f\u5f03');\n        }\n\n        \/\/ \u663e\u793a\u9519\u8bef\u4fe1\u606f\n        function displayErrorInfo(provider, error) {\n            if (provider === 'siliconflow') {\n                resultText.innerHTML = `\u8f6c\u6362\u5931\u8d25\u3002\u8bf7\u68c0\u67e5\uff1a\n1. API\u5bc6\u94a5\u662f\u5426\u6b63\u786e\n2. \u7f51\u7edc\u8fde\u63a5\u662f\u5426\u6b63\u5e38\n3. \u97f3\u9891\u6587\u4ef6\u683c\u5f0f\u662f\u5426\u652f\u6301\n\n\u9519\u8bef\u8be6\u60c5\uff1a${error.message}`;\n            } else if (provider === 'volcengine') {\n                \/\/ \u68c0\u67e5\u662f\u5426\u662f\u97f3\u9891\u4e0b\u8f7d\u5931\u8d25\u7684\u9519\u8bef\n                if (error.message.includes('audio download failed') || error.message.includes('Invalid audio URI')) {\n                    resultText.innerHTML = `\n&lt;div style=\"color: #e74c3c; margin-bottom: 15px;\">\n&lt;strong>\u274c \u97f3\u9891\u6587\u4ef6\u4e0b\u8f7d\u5931\u8d25&lt;\/strong>\n&lt;\/div>\n\n&lt;div style=\"background: #fff3cd; padding: 15px; border-radius: 8px; border-left: 4px solid #ffc107; margin-bottom: 15px;\">\n&lt;strong>\ud83d\udd0d \u95ee\u9898\u539f\u56e0\uff1a&lt;\/strong>&lt;br>\n\u60a8\u63d0\u4f9b\u7684URL\u4e0d\u662f\u6709\u6548\u7684\u97f3\u9891\u6587\u4ef6\u76f4\u94fe\u3002\u706b\u5c71\u5f15\u64ceAPI\u65e0\u6cd5\u76f4\u63a5\u4e0b\u8f7d\u8be5\u6587\u4ef6\u3002\n&lt;\/div>\n\n&lt;div style=\"background: #d1ecf1; padding: 15px; border-radius: 8px; border-left: 4px solid #bee5eb; margin-bottom: 15px;\">\n&lt;strong>\u2705 \u89e3\u51b3\u65b9\u6848\uff1a&lt;\/strong>&lt;br>\n&lt;br>\n&lt;strong>1. \u68c0\u67e5URL\u662f\u5426\u4e3a\u76f4\u94fe\uff1a&lt;\/strong>&lt;br>\n\u2022 \u5728\u6d4f\u89c8\u5668\u4e2d\u76f4\u63a5\u6253\u5f00\u60a8\u7684URL&lt;br>\n\u2022 \u5982\u679c\u76f4\u63a5\u5f00\u59cb\u4e0b\u8f7d\/\u64ad\u653e\u97f3\u9891\u6587\u4ef6\uff0c\u5219\u4e3a\u6709\u6548\u76f4\u94fe&lt;br>\n\u2022 \u5982\u679c\u8df3\u8f6c\u5230\u767b\u5f55\u9875\u9762\u6216\u5206\u4eab\u9875\u9762\uff0c\u5219\u4e3a\u65e0\u6548\u94fe\u63a5&lt;br>\n&lt;br>\n&lt;strong>2. \u83b7\u53d6\u6709\u6548\u76f4\u94fe\u7684\u65b9\u6cd5\uff1a&lt;\/strong>&lt;br>\n\u2022 &lt;strong>GitHub\u65b9\u5f0f\uff1a&lt;\/strong>\u4e0a\u4f20\u5230GitHub\u4ed3\u5e93\uff0c\u70b9\u51fb\u6587\u4ef6\u2192Raw\uff0c\u590d\u5236\u94fe\u63a5&lt;br>\n\u2022 &lt;strong>\u81ea\u6709\u670d\u52a1\u5668\uff1a&lt;\/strong>\u4e0a\u4f20\u5230\u60a8\u7684\u7f51\u7ad9\u670d\u52a1\u5668&lt;br>\n\u2022 &lt;strong>\u4e13\u4e1aCDN\uff1a&lt;\/strong>\u4f7f\u7528\u963f\u91cc\u4e91OSS\u3001\u817e\u8baf\u4e91COS\u7b49\u670d\u52a1&lt;br>\n\u2022 &lt;strong>\u514d\u8d39\u6258\u7ba1\uff1a&lt;\/strong>\u5207\u6362\u5230\"\u901a\u8fc7\u4e0a\u4f20\u670d\u52a1\u83b7\u53d6URL\"\u6a21\u5f0f&lt;br>\n&lt;\/div>\n\n&lt;div style=\"background: #f8d7da; padding: 10px; border-radius: 8px; border-left: 4px solid #dc3545;\">\n&lt;strong>\u26a0\ufe0f \u4ee5\u4e0b\u94fe\u63a5\u7c7b\u578b\u65e0\u6548\uff1a&lt;\/strong>&lt;br>\n\u2022 \u767e\u5ea6\u7f51\u76d8\u3001OneDrive\u3001GoogleDrive\u5206\u4eab\u94fe\u63a5&lt;br>\n\u2022 \u9700\u8981\u767b\u5f55\u9a8c\u8bc1\u7684\u94fe\u63a5&lt;br>\n\u2022 \u91cd\u5b9a\u5411\u94fe\u63a5&lt;br>\n&lt;\/div>\n\n&lt;strong>\u9519\u8bef\u8be6\u60c5\uff1a&lt;\/strong> ${error.message}`;\n                } else {\n                    resultText.innerHTML = `\u8f6c\u6362\u5931\u8d25\u3002\u8bf7\u68c0\u67e5\uff1a\n1. \u706b\u5c71\u5f15\u64ce APP ID \u548c Access Token \u662f\u5426\u6b63\u786e\n2. \u7f51\u7edc\u8fde\u63a5\u662f\u5426\u6b63\u5e38\n3. \u97f3\u9891\u6587\u4ef6URL\u662f\u5426\u4e3a\u6709\u6548\u7684\u76f4\u94fe\u5730\u5740\n\n\u9519\u8bef\u8be6\u60c5\uff1a${error.message}`;\n                }\n            }\n        }\n\n        \/\/ \u9a8c\u8bc1URL\u662f\u5426\u4e3a\u6709\u6548\u76f4\u94fe\n        function validateUrl() {\n            const url = directAudioUrlInput.value.trim();\n            const resultDiv = urlValidationResult;\n            resultDiv.style.display = 'none'; \/\/ \u9690\u85cf\u4e4b\u524d\u7684\u7ed3\u679c\n\n            if (!url) {\n                resultDiv.textContent = '\u8bf7\u5148\u8f93\u5165URL';\n                resultDiv.style.display = 'block';\n                return;\n            }\n\n            if (url.startsWith('http:\/\/') || url.startsWith('https:\/\/')) {\n                resultDiv.textContent = '\u2705 \u8fd9\u662f\u4e00\u4e2a\u6709\u6548\u7684\u76f4\u94feURL\uff01';\n                resultDiv.style.color = 'green';\n                resultDiv.style.fontWeight = 'bold';\n                resultDiv.style.display = 'block';\n            } else {\n                resultDiv.textContent = '\u274c \u8fd9\u4e0d\u662f\u4e00\u4e2a\u6709\u6548\u7684\u76f4\u94feURL\u3002\u8bf7\u786e\u4fdd\u5b83\u4ee5 http:\/\/ \u6216 https:\/\/ \u5f00\u5934\u3002';\n                resultDiv.style.color = 'red';\n                resultDiv.style.fontWeight = 'bold';\n                resultDiv.style.display = 'block';\n            }\n        }\n\n        \/\/ \u5904\u7406\u6587\u4ef6\u4e0a\u4f20\n        audioFileInput.addEventListener('change', async (event) => {\n            const file = event.target.files&#91;0];\n            if (file) {\n                console.log('\u9009\u62e9\u7684\u6587\u4ef6:', file.name, file.type, file.size);\n                \n                \/\/ \u68c0\u67e5\u6587\u4ef6\u7c7b\u578b\n                if (!file.type.startsWith('audio\/')) {\n                    showStatus('\u274c \u8bf7\u9009\u62e9\u97f3\u9891\u6587\u4ef6', 'error');\n                    return;\n                }\n\n                \/\/ \u68c0\u67e5\u6587\u4ef6\u5927\u5c0f\uff08\u9650\u5236\u4e3a50MB\uff09\n                if (file.size > 50 * 1024 * 1024) {\n                    showStatus('\u274c \u6587\u4ef6\u8fc7\u5927\uff0c\u8bf7\u9009\u62e9\u5c0f\u4e8e50MB\u7684\u97f3\u9891\u6587\u4ef6', 'error');\n                    return;\n                }\n\n                currentAudioBlob = file;\n                \n                \/\/ \u663e\u793a\u97f3\u9891\u64ad\u653e\u5668\n                const audioUrl = URL.createObjectURL(file);\n                audioPlayer.src = audioUrl;\n                audioPlayer.style.display = 'block';\n                \n                \/\/ \u663e\u793a\u5f00\u59cb\u8f6c\u6362\u6309\u94ae\n                updateConvertButtonState(); \/\/ \u66f4\u65b0\u6309\u94ae\u72b6\u6001\n            }\n        });\n\n        \/\/ \u4e8b\u4ef6\u76d1\u542c\u5668\n        convertBtn.addEventListener('click', () => {\n            console.log('\u70b9\u51fb\u8f6c\u6362\u6309\u94ae');\n            convertToText();\n        });\n        \n        exportBtn.addEventListener('click', () => {\n            console.log('\u70b9\u51fb\u5bfc\u51fa\u6309\u94ae');\n            exportToTxt();\n        });\n        \n        \/\/ toggleView.addEventListener('click', toggleViewMode); \/\/ \u79fb\u9664\u89c6\u56fe\u5207\u6362\u6309\u94ae\u76d1\u542c\u5668\n        apiProvider.addEventListener('change', switchApiProvider);\n        audioUrlMethod.addEventListener('change', switchAudioUrlMethod);\n        directAudioUrlInput.addEventListener('input', updateConvertButtonState); \/\/ \u6dfb\u52a0URL\u8f93\u5165\u76d1\u542c\u5668\n        validateUrlBtn.addEventListener('click', validateUrl); \/\/ \u6dfb\u52a0URL\u9a8c\u8bc1\u6309\u94ae\u76d1\u542c\u5668\n\n        \/\/ \u9875\u9762\u52a0\u8f7d\u5b8c\u6210\u540e\u7684\u521d\u59cb\u5316\n        document.addEventListener('DOMContentLoaded', () => {\n            console.log('\u9875\u9762\u52a0\u8f7d\u5b8c\u6210');\n            showStatus('\ud83d\udd27 \u8bf7\u9009\u62e9API\u670d\u52a1\u5546\u5e76\u914d\u7f6e\u76f8\u5173\u4fe1\u606f\u3002', 'info');\n            \n            \/\/ \u521d\u59cb\u5316\u89c6\u56fe\n            \/\/ toggleView.style.display = 'none'; \/\/ \u79fb\u9664\u89c6\u56fe\u5207\u6362\u6309\u94ae\n            convertBtn.style.display = 'none';\n            exportBtn.style.display = 'none';\n            switchApiProvider(); \/\/ \u521d\u59cb\u5316API\u914d\u7f6e\u663e\u793a\n            \n            \/\/ \u4e3a\u9009\u62e9\u7684\u8f93\u5165\u6846\u6dfb\u52a0\u76d1\u542c\u5668\u4ee5\u5b9e\u65f6\u66f4\u65b0\u6309\u94ae\u72b6\u6001\n            document.getElementById('apiKey').addEventListener('input', updateConvertButtonState);\n            document.getElementById('volcAppKey').addEventListener('input', updateConvertButtonState);\n            document.getElementById('volcAccessKey').addEventListener('input', updateConvertButtonState);\n        });\n    &lt;\/script>\n&lt;\/body>\n&lt;\/html><\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24],"tags":[16,13],"class_list":["post-57","post","type-post","status-publish","format-standard","hentry","category-articles","tag-api","tag-13"],"_links":{"self":[{"href":"https:\/\/en.blog.liu-qi.cn\/index.php\/wp-json\/wp\/v2\/posts\/57","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/en.blog.liu-qi.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/en.blog.liu-qi.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/en.blog.liu-qi.cn\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/en.blog.liu-qi.cn\/index.php\/wp-json\/wp\/v2\/comments?post=57"}],"version-history":[{"count":0,"href":"https:\/\/en.blog.liu-qi.cn\/index.php\/wp-json\/wp\/v2\/posts\/57\/revisions"}],"wp:attachment":[{"href":"https:\/\/en.blog.liu-qi.cn\/index.php\/wp-json\/wp\/v2\/media?parent=57"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/en.blog.liu-qi.cn\/index.php\/wp-json\/wp\/v2\/categories?post=57"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/en.blog.liu-qi.cn\/index.php\/wp-json\/wp\/v2\/tags?post=57"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}