纯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();
相关推荐
子兮曰5 小时前
Bun v1.3.14 深度解析:Image API、HTTP/3、全局虚拟存储与五十项变革
前端·后端·bun
kyriewen6 小时前
今天,百年巨头一次砍了9200人,而一个离职科学家的实话让全网睡不着觉
前端·openai·ai编程
问心无愧05137 小时前
ctf show web 入门42
android·前端·android studio
kyriewen7 小时前
老板逼我上AI,我偷偷在浏览器里跑LLaMA,省下20万API费
前端·react.js·llm
Beginner x_u7 小时前
前端八股整理(手写 02)|数组转树、数组扁平化、随机打乱一个数组
前端·数组·数组转树·数组扁平化
KaMeidebaby7 小时前
卡梅德生物技术快报|禽类成纤维细胞 FISH 实验:鸟类性别染色体基因定位技术实现与数据验证
前端·数据库·其他·百度·新浪微博
天若有情6737 小时前
前端高阶性能优化:跳出传统懒加载与预加载,基于用户行为做轻量预判加载
前端·性能优化
视觉&物联智能8 小时前
【杂谈】-当人工智能能力增速凌驾于安全管控模型之上
人工智能·安全·ai·chatgpt·agi·deepseek
小小小小宇8 小时前
前端转后端:SQL 是什么
前端
张元清9 小时前
React Observer Hooks:7 种监听 DOM 而不写样板代码的方式
前端·javascript·面试