纯JS完成CHATGPT流式输出

html 复制代码
<!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>

完成比较简陋,需要的自己美化界面。流式输出,存储本地列表。

javascript 复制代码
        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;
           }
       }

        // 保存对话记录到localStorage
        function saveToHistory(question, answer) {
            const chatHistory = JSON.parse(localStorage.getItem('chatHistory')) || [];
            chatHistory.push({ question, answer });
            localStorage.setItem('chatHistory', JSON.stringify(chatHistory));
            loadHistory();
        }

        // 初次加载历史记录
        loadHistory();
相关推荐
~甲壳虫1 小时前
react中得类组件和函数组件有啥区别,怎么理解这两个函数
前端·react.js·前端框架
.net开发1 小时前
WPF使用Prism框架首页界面
前端·c#·.net·wpf
名字越长技术越强1 小时前
vue--vueCLI
前端·javascript·vue.js
是个热心市民1 小时前
构建一个导航栏web
前端·javascript·python·django·html
J不A秃V头A2 小时前
报错:npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。
前端·npm·node.js
GDAL2 小时前
npm入门教程14:npm依赖管理
前端·npm·node.js
余生H2 小时前
即时可玩web小游戏(二):打砖块(支持移动端版) - 集成InsCode快来阅读并即时体验吧~
前端·javascript·inscode·canvas·h5游戏
开发者每周简报2 小时前
ChatGPT o1与GPT-4o、Claude 3.5 Sonnet和Gemini 1.5 Pro的比较
人工智能·gpt·chatgpt
5335ld2 小时前
vue+exceljs前端下载、导出xlsx文件
前端·vue.js
摇头的金丝猴2 小时前
uniapp vue3 使用echarts-gl 绘画3d图表
前端·uni-app·echarts