纯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();
相关推荐
gnip3 小时前
企业级配置式表单组件封装
前端·javascript·vue.js
一只叫煤球的猫4 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
excel5 小时前
Three.js 材质(Material)详解 —— 区别、原理、场景与示例
前端
掘金安东尼5 小时前
抛弃自定义模态框:原生Dialog的实力
前端·javascript·github
hj5914_前端新手9 小时前
javascript基础- 函数中 this 指向、call、apply、bind
前端·javascript
薛定谔的算法9 小时前
低代码编辑器项目设计与实现:以JSON为核心的数据驱动架构
前端·react.js·前端框架
Hilaku9 小时前
都2025年了,我们还有必要为了兼容性,去写那么多polyfill吗?
前端·javascript·css
yangcode9 小时前
iOS 苹果内购 Storekit 2
前端
LuckySusu9 小时前
【js篇】JavaScript 原型修改 vs 重写:深入理解 constructor的指向问题
前端·javascript
LuckySusu9 小时前
【js篇】如何准确获取对象自身的属性?hasOwnProperty深度解析
前端·javascript