<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Chat with OpenAI</title><style>body {font-family: Arial, sans-serif;max-width: 600px;margin: 50px auto;}#input-section, #history-section {margin-bottom: 20px;}#output {padding: 10px;background-color: #f1f1f1;min-height: 50px;margin-top: 10px;white-space: pre-wrap;}#history {padding: 10px;background-color: #f9f9f9;margin-top: 20px;border: 1px solid #ddd;}</style>
</head>
<body><h2>Chat with OpenAI</h2><div id="input-section"><input type="text" id="user-input" placeholder="Type your question..." style="width: 80%;"><button onclick="sendMessage()">Send</button></div><div id="output"></div><div id="history-section"><h3>Chat History</h3><div id="history"></div></div><script>//JS部分详见下面</script>
</body>
</html>
完成比较简陋,需要的自己美化界面。流式输出,存储本地列表。
const API_KEY = ''; // 替换为你的OpenAI API密钥const API_URL = '';// 获取并展示本地历史记录function loadHistory() {const historyContainer = document.getElementById('history');const chatHistory = JSON.parse(localStorage.getItem('chatHistory')) || [];historyContainer.innerHTML = '';chatHistory.forEach(entry => {const question = document.createElement('p');question.textContent = `Q: ${entry.question}`;const answer = document.createElement('p');answer.textContent = `A: ${entry.answer}`;historyContainer.appendChild(question);historyContainer.appendChild(answer);historyContainer.appendChild(document.createElement('hr'));});}// 发送用户问题并流式获取答案async function sendMessage() {const userInput = document.getElementById('user-input').value;if (!userInput) return;document.getElementById('output').textContent = 'Thinking...';document.getElementById('user-input').value = '';try {const response = await fetch(API_URL, {method: "POST",headers: {"Content-Type": "application/json","Authorization": `Bearer ${API_KEY}`},body: JSON.stringify({model: "gpt-3.5-turbo",messages: [{"role": "user", "content": userInput}],stream: true})});const reader = response.body.getReader();const decoder = new TextDecoder("utf-8");let responseText = '';document.getElementById('output').textContent = '';while (true) {const { done, value } = await reader.read();if (done) break;// 将流返回的数据块转为文本const chunk = decoder.decode(value, { stream: true });// 解析流返回的JSON字符串const lines = chunk.trim().split("\n");for (const line of lines) {if (line.startsWith("data:")) {const jsonStr = line.replace("data: ", "").trim();if (jsonStr !== "[DONE]") {const parsedData = JSON.parse(jsonStr);const content = parsedData.choices[0].delta.content || '';responseText += content;document.getElementById('output').textContent = responseText;}}}}saveToHistory(userInput, responseText);} catch (error) {document.getElementById('output').textContent = 'Error: ' + error.message;}}// 保存对话记录到localStoragefunction saveToHistory(question, answer) {const chatHistory = JSON.parse(localStorage.getItem('chatHistory')) || [];chatHistory.push({ question, answer });localStorage.setItem('chatHistory', JSON.stringify(chatHistory));loadHistory();}// 初次加载历史记录loadHistory();