func InitHeader(w http.ResponseWriter) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
    w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, Authorization")
}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>聊天演示 - 流式/非流式输出</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f5f5f5;
        }

        .container {
            background: white;
            border-radius: 10px;
            padding: 20px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }

        .header {
            text-align: center;
            margin-bottom: 30px;
            color: #333;
        }

        .input-section {
            margin-bottom: 20px;
        }

        .input-group {
            margin-bottom: 15px;
        }

        label {
            display: block;
            margin-bottom: 5px;
            font-weight: 500;
            color: #555;
        }

        input, textarea, select {
            width: 100%;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
            font-size: 14px;
            box-sizing: border-box;
        }

        textarea {
            resize: vertical;
            min-height: 100px;
        }

        .button-group {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
        }

        button {
            flex: 1;
            padding: 12px;
            border: none;
            border-radius: 5px;
            font-size: 14px;
            font-weight: 500;
            cursor: pointer;
            transition: all 0.2s;
        }

        .btn-stream {
            background-color: #007AFF;
            color: white;
        }

        .btn-stream:hover {
            background-color: #0056D6;
        }

        .btn-normal {
            background-color: #34C759;
            color: white;
        }

        .btn-normal:hover {
            background-color: #28A745;
        }

        .btn-clear {
            background-color: #FF3B30;
            color: white;
        }

        .btn-clear:hover {
            background-color: #D70015;
        }

        button:disabled {
            opacity: 0.6;
            cursor: not-allowed;
        }

        .output-section {
            border-top: 1px solid #eee;
            padding-top: 20px;
        }

        .output-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
        }

        .output-title {
            font-weight: 600;
            color: #333;
        }

        .status-indicator {
            padding: 4px 8px;
            border-radius: 12px;
            font-size: 12px;
            font-weight: 500;
        }

        .status-waiting {
            background-color: #F2F2F7;
            color: #8E8E93;
        }

        .status-streaming {
            background-color: #E3F2FD;
            color: #1976D2;
        }

        .status-completed {
            background-color: #E8F5E8;
            color: #2E7D32;
        }

        .status-error {
            background-color: #FFEBEE;
            color: #C62828;
        }

        .output-box {
            background-color: #f8f9fa;
            border: 1px solid #e9ecef;
            border-radius: 5px;
            padding: 15px;
            min-height: 200px;
            font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', monospace;
            font-size: 13px;
            line-height: 1.5;
            white-space: pre-wrap;
            overflow-y: auto;
            max-height: 400px;
        }

        .loading {
            display: inline-block;
            animation: pulse 1.5s ease-in-out infinite;
        }

        @keyframes pulse {
            0% { opacity: 1; }
            50% { opacity: 0.5; }
            100% { opacity: 1; }
        }

        .error {
            color: #d32f2f;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>聊天演示</h1>
            <p>测试流式和非流式输出</p>
        </div>

        <div class="input-section">
            <div class="input-group">
                <label for="model">模型:</label>
                <input type="text" id="model" value="doubao-seed-1-6-251015">
            </div>

            <div class="input-group">
                <label for="message">消息:</label>
                <textarea id="message" placeholder="请输入您的问题...">50字介绍勾股定理</textarea>
            </div>

            <div class="input-group">
                <label for="msgId">消息ID:</label>
                <input type="text" id="msgId" value="666">
            </div>
        </div>

        <div class="button-group">
            <button class="btn-stream" onclick="sendStreamRequest()">流式输出</button>
            <button class="btn-normal" onclick="sendNormalRequest()">普通输出</button>
            <button class="btn-clear" onclick="clearOutput()">清空输出</button>
        </div>

        <div class="output-section">
            <div class="output-header">
                <span class="output-title">响应结果</span>
                <span id="status" class="status-indicator status-waiting">等待中</span>
            </div>
            <div id="output" class="output-box">等待发送请求...</div>
        </div>
    </div>

    <script>
        const API_URL = 'http://localhost:8080/chat/send';

        function updateStatus(status, text) {
            const statusElement = document.getElementById('status');
            statusElement.className = `status-indicator status-${status}`;
            statusElement.textContent = text;
        }

        function appendOutput(text, replace = false) {
            const outputElement = document.getElementById('output');
            if (replace) {
                outputElement.textContent = text;
            } else {
                outputElement.textContent += text;
            }
            outputElement.scrollTop = outputElement.scrollHeight;
        }

        function getRequestData() {
            return {
                model: document.getElementById('model').value,
                message: document.getElementById('message').value,
                msgId: document.getElementById('msgId').value,
                stream: true
            };
        }

        function setButtonsDisabled(disabled) {
            document.querySelectorAll('button').forEach(btn => {
                btn.disabled = disabled;
            });
        }

        async function sendStreamRequest() {
            const data = { ...getRequestData(), stream: true };

            try {
                setButtonsDisabled(true);
                updateStatus('streaming', '流式输出中...');
                appendOutput('', true);

                const response = await fetch(API_URL, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify(data)
                });

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

                const reader = response.body.getReader();
                const decoder = new TextDecoder();

                while (true) {
                    const { done, value } = await reader.read();

                    if (done) {
                        updateStatus('completed', '流式输出完成');
                        break;
                    }

                    const chunk = decoder.decode(value, { stream: true });
                    const lines = chunk.split('\n');

                    for (const line of lines) {
                        if (line.trim()) {
                            if (line.startsWith('data: ')) {
                                const data = line.slice(6);
                                if (data === '[DONE]') {
                                    updateStatus('completed', '流式输出完成');
                                    break;
                                }
                                try {
                                    const parsed = JSON.parse(data);
                                    if (parsed.content) {
                                        appendOutput(parsed.content);
                                    }
                                } catch (e) {
                                    appendOutput(data);
                                }
                            }
                        }
                    }
                }

            } catch (error) {
                console.error('流式请求错误:', error);
                updateStatus('error', '请求失败');
                appendOutput(`错误: ${error.message}`, true);
            } finally {
                setButtonsDisabled(false);
            }
        }

        async function sendNormalRequest() {
            const data = { ...getRequestData(), stream: false };

            try {
                setButtonsDisabled(true);
                updateStatus('streaming', '请求处理中...');
                appendOutput('正在处理请求...', true);

                const response = await fetch(API_URL, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify(data)
                });

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

                const result = await response.json();

                updateStatus('completed', '请求完成');
                appendOutput(JSON.stringify(result, null, 2), true);

            } catch (error) {
                console.error('普通请求错误:', error);
                updateStatus('error', '请求失败');
                appendOutput(`错误: ${error.message}`, true);
            } finally {
                setButtonsDisabled(false);
            }
        }

        function clearOutput() {
            appendOutput('等待发送请求...', true);
            updateStatus('waiting', '等待中');
        }

        // 自动生成随机消息ID
        function generateMsgId() {
            document.getElementById('msgId').value = Date.now().toString();
        }

        // 页面加载时生成随机ID
        window.onload = function() {
            generateMsgId();
        }

        // 双击消息ID输入框生成新ID
        document.getElementById('msgId').addEventListener('dblclick', generateMsgId);
    </script>
</body>
</html>
作者:admin  创建时间:2025-11-16 23:06
最后编辑:admin  更新时间:2025-11-16 23:16
上一篇:
下一篇: