imetting_backend/test/stream_test.html

1 line
8.8 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>\n<html>\n<head>\n <title>流式LLM测试</title>\n <meta charset=\"utf-8\">\n <style>\n body {\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n max-width: 800px;\n margin: 0 auto;\n padding: 20px;\n background-color: #f5f5f5;\n }\n .container {\n background: white;\n border-radius: 8px;\n padding: 20px;\n box-shadow: 0 2px 10px rgba(0,0,0,0.1);\n }\n h1 {\n color: #333;\n text-align: center;\n }\n .controls {\n display: flex;\n gap: 10px;\n margin-bottom: 20px;\n align-items: flex-end;\n }\n .form-group {\n flex: 1;\n }\n label {\n display: block;\n margin-bottom: 5px;\n font-weight: bold;\n color: #555;\n }\n input, textarea {\n width: 100%;\n padding: 8px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 14px;\n }\n button {\n padding: 10px 20px;\n background: #667eea;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n transition: background 0.3s;\n }\n button:hover {\n background: #5a6fd8;\n }\n button:disabled {\n background: #ccc;\n cursor: not-allowed;\n }\n .output {\n background: #f8f9fa;\n border: 1px solid #e9ecef;\n border-radius: 4px;\n padding: 15px;\n min-height: 200px;\n white-space: pre-wrap;\n font-family: 'Courier New', monospace;\n line-height: 1.6;\n overflow-y: auto;\n max-height: 500px;\n }\n .status {\n margin: 10px 0;\n padding: 8px;\n border-radius: 4px;\n }\n .status.info {\n background: #d1ecf1;\n color: #0c5460;\n }\n .status.error {\n background: #f8d7da;\n color: #721c24;\n }\n .status.success {\n background: #d4edda;\n color: #155724;\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <h1>🤖 流式LLM总结测试</h1>\n \n <div class=\"controls\">\n <div class=\"form-group\">\n <label>会议ID:</label>\n <input type=\"number\" id=\"meetingId\" value=\"38\" min=\"1\">\n </div>\n <div class=\"form-group\">\n <label>用户提示词:</label>\n <textarea id=\"userPrompt\" rows=\"2\" placeholder=\"请重点关注决策事项和待办任务\">请重点关注决策事项和待办任务</textarea>\n </div>\n <button id=\"streamBtn\">🚀 开始流式生成</button>\n <button id=\"normalBtn\">📝 普通生成</button>\n <button id=\"clearBtn\">🗑️ 清空</button>\n </div>\n \n <div id=\"status\" class=\"status\" style=\"display: none;\"></div>\n <div class=\"output\" id=\"output\">点击按钮开始测试...</div>\n </div>\n\n <script>\n const meetingIdInput = document.getElementById('meetingId');\n const userPromptInput = document.getElementById('userPrompt');\n const streamBtn = document.getElementById('streamBtn');\n const normalBtn = document.getElementById('normalBtn');\n const clearBtn = document.getElementById('clearBtn');\n const output = document.getElementById('output');\n const status = document.getElementById('status');\n\n function showStatus(message, type = 'info') {\n status.textContent = message;\n status.className = `status ${type}`;\n status.style.display = 'block';\n }\n\n function hideStatus() {\n status.style.display = 'none';\n }\n\n // 流式生成\n streamBtn.addEventListener('click', async () => {\n const meetingId = meetingIdInput.value;\n const userPrompt = userPromptInput.value;\n \n if (!meetingId) {\n showStatus('请输入会议ID', 'error');\n return;\n }\n\n streamBtn.disabled = true;\n normalBtn.disabled = true;\n output.textContent = '';\n showStatus('正在连接流式接口...', 'info');\n\n try {\n const response = await fetch(`http://localhost:8000/api/meetings/${meetingId}/generate-summary-stream`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer your_token_here' // 需要替换为实际token\n },\n body: JSON.stringify({ user_prompt: userPrompt })\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n showStatus('📡 正在接收流式数据...', 'info');\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n const lines = chunk.split('\\n');\n \n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const data = JSON.parse(line.slice(6));\n if (data.content) {\n output.textContent += data.content;\n output.scrollTop = output.scrollHeight;\n } else if (data.error) {\n showStatus(`错误: ${data.error}`, 'error');\n break;\n } else if (data.done) {\n showStatus('✅ 流式生成完成!', 'success');\n }\n } catch (e) {\n // 忽略无效的JSON数据\n }\n }\n }\n }\n\n } catch (error) {\n showStatus(`连接失败: ${error.message}`, 'error');\n console.error('Stream error:', error);\n } finally {\n streamBtn.disabled = false;\n normalBtn.disabled = false;\n }\n });\n\n // 普通生成\n normalBtn.addEventListener('click', async () => {\n const meetingId = meetingIdInput.value;\n const userPrompt = userPromptInput.value;\n \n if (!meetingId) {\n showStatus('请输入会议ID', 'error');\n return;\n }\n\n streamBtn.disabled = true;\n normalBtn.disabled = true;\n output.textContent = '';\n showStatus('正在调用普通接口...', 'info');\n\n try {\n const response = await fetch(`http://localhost:8000/api/meetings/${meetingId}/generate-summary`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer your_token_here' // token\n },\n body: JSON.stringify({ user_prompt: userPrompt })\n });\n\n const result = await response.json();\n\n if (response.ok) {\n output.textContent = result.content;\n showStatus(' ', 'success');\n } else {\n showStatus(`: ${result.detail}`, 'error');\n }\n\n } catch (error) {\n showStatus(`: ${error.message}`, 'error');\n console.error('Request error:', error);\n } finally {\n streamBtn.disabled = false;\n normalBtn.disabled = false;\n }\n });\n\n // \n clearBtn.addEventListener('click', () => {\n output.textContent = '...';\n hideStatus();\n });\n </script>\n</body>\n</html>