node.js+html调用ChatGPTApi实现Ai网站demo(带源码)
- 软件开发
 - 2025-09-07 13:18:01
 

文章目录 前言一、demo演示二、node.js 使用步骤1.引入库2.引入包 前端HTML调用接口和UI所有文件总结
前言
关注博主,学习每天一个小demo 今天是Ai对话网站
又到了每天一个小demo的时候咯,前面我写了多人实时对话demo、和视频转换demo,今天我来使用 node.js + html 调用chatGpt Api实现一个Ai 流式对话小demo,当然现在主流的各种APi调用方式一致,你也可以接入deepseek,或者第三方的接口,效果一样
一、demo演示
下面是一个简单的demo演示,并且是支持流式的
二、node.js 使用步骤 1.引入库代码如下:
先初始化一个package.js 文件。
npm init -y我们需要安装 express、cors、openAi、dotenv三方库
{ "name": "web", "version": "1.0.0", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node server.js" }, "keywords": [], "author": "", "license": "ISC", "description": "", "dependencies": { "axios": "^1.7.9", "cors": "^2.8.5", "dotenv": "^16.0.3", "express": "^4.18.2", "openai": "^4.0.0" } } 2.引入包创建server.js 引入我们的第三方包 编写接口逻辑
**特别关注:
baseURL: 这里大家可以替换其他的APi 比如deepseek(好像目前不能充值了),或者一些第三方的API地址。apiKey: 这里大家把key可以直接填写上,我这里为了学习知识,新建了一个.env 文件。** const express = require('express'); const cors = require('cors'); const OpenAI = require('openai'); require('dotenv').config(); const app = express(); app.use(express.json()); app.use(cors()); // 初始化OpenAI客户端 const openai = new OpenAI({ apiKey: process.env.DEEPSEEK_API_KEY, baseURL: " api.openai /v1" // 使用OpenAI官方API地址 这里可以可以使用别的Api地址 // 比如 deepseek 或者其他的第三方的一些 // baseURL: " api.deepseek /v1" }); let conversationHistory = []; app.post('/chat', async (req, res) => { try { const { message } = req.body; // 设置响应头,支持流式输出 res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); res.setHeader('Access-Control-Allow-Origin', '*'); // 添加CORS支持 // 添加用户消息到历史记录 conversationHistory.push({ role: "user", content: message }); const stream = await openai.chat pletions.create({ model: "gpt-3.5-turbo", messages: [ { role: "system", content: "You are a helpful assistant." }, ...conversationHistory ], temperature: 0.7, max_tokens: 1000, stream: true, }); let fullResponse = ''; // 确保每次写入后立即刷新缓冲区 for await (const chunk of stream) { const content = chunk.choices[0]?.delta?.content || ''; if (content) { fullResponse += content; const dataToSend = JSON.stringify({ content }); console.log('Sending to client:', dataToSend); res.write(`data: ${dataToSend}\n\n`); // 强制刷新缓冲区 if (res.flush) { res.flush(); } } } // 将完整回复添加到对话历史 conversationHistory.push({ role: "assistant", content: fullResponse }); if (conversationHistory.length > 10) { conversationHistory = conversationHistory.slice(-10); } res.write('data: [DONE]\n\n'); if (res.flush) { res.flush(); } res.end(); } catch (error) { console.error('Error:', error); res.write(`data: ${JSON.stringify({ error: '服务器错误' })}\n\n`); res.end(); } }); const PORT = 3000; app.listen(PORT, () => { console.log(`服务器运行在端口 ${PORT}`); });在根目录执行 node server.js 启动服务
前端HTML调用接口和UI不墨迹哈,直接把所有代码贴过来 大家好直接研究代码,我就不用一行一行解读了,没啥东西,难处就是对流式数据的一个处理
特别注意, 不要直接点击html打开页面,在vscode里面安装扩展Live Server,然后点击右下角 Go live启动一个微服务。
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ChatGPT 聊天</title> <style> #chat-container { width: 80%; max-width: 800px; margin: 20px auto; padding: 20px; border: 1px solid #ccc; border-radius: 5px; } #chat-messages { height: 400px; overflow-y: auto; margin-bottom: 20px; padding: 10px; border: 1px solid #eee; } .message { margin: 10px 0; padding: 10px; border-radius: 5px; } .user-message { background-color: #e3f2fd; margin-left: 20%; } .bot-message { background-color: #f5f5f5; margin-right: 20%; } #message-form { display: flex; gap: 10px; } #message-input { flex: 1; padding: 8px; } .typing { opacity: 0.5; } .cursor { display: inline-block; width: 2px; height: 15px; background: #000; margin-left: 2px; animation: blink 1s infinite; } @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } } </style> </head> <body> <div id="chat-container"> <div id="chat-messages"></div> <form id="message-form"> <input type="text" id="message-input" placeholder="输入消息..." required> <button type="submit" id="submit-btn">发送</button> </form> </div> <script> const messageForm = document.getElementById('message-form'); const messageInput = document.getElementById('message-input'); const chatMessages = document.getElementById('chat-messages'); const submitBtn = document.getElementById('submit-btn'); messageForm.addEventListener('submit', async (e) => { e.preventDefault(); const message = messageInput.value.trim(); if (!message) return; // 禁用输入和发送按钮 messageInput.disabled = true; submitBtn.disabled = true; // 显示用户消息 addMessage(message, 'user'); messageInput.value = ''; // 创建机器人回复的消息框 const botMessageDiv = document.createElement('div'); botMessageDiv.className = 'message bot-message typing'; chatMessages.appendChild(botMessageDiv); // 添加光标 const cursor = document.createElement('span'); cursor.className = 'cursor'; botMessageDiv.appendChild(cursor); try { const response = await fetch('http://localhost:3000/chat', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'text/event-stream' }, body: JSON.stringify({ message }) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let botResponse = ''; let buffer = ''; try { while (true) { const { value, done } = await reader.read(); // 如果流结束了,就退出循环 if (done) { console.log('Stream complete'); break; } // 确保有值才处理 if (value) { buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); // 保留最后一个不完整的行 buffer = lines.pop() || ''; for (const line of lines) { if (line.trim() === '') continue; if (!line.startsWith('data: ')) continue; const data = line.slice(6).trim(); if (data === '[DONE]') { botMessageDiv.classList.remove('typing'); cursor.remove(); continue; } try { const parsedData = JSON.parse(data); if (parsedData.content) { botResponse += parsedData.content; botMessageDiv.textContent = botResponse; botMessageDiv.appendChild(cursor); chatMessages.scrollTop = chatMessages.scrollHeight; } } catch (e) { console.error('JSON解析错误:', e, 'Raw data:', data); } } } } // 处理最后可能残留的数据 if (buffer.trim()) { const finalText = decoder.decode(); // 完成流的解码 if (finalText) { buffer += finalText; const lines = buffer.split('\n'); for (const line of lines) { if (line.trim() === '' || !line.startsWith('data: ')) continue; const data = line.slice(6).trim(); if (data === '[DONE]') continue; try { const parsedData = JSON.parse(data); if (parsedData.content) { botResponse += parsedData.content; botMessageDiv.textContent = botResponse; } } catch (e) { console.error('最终解析错误:', e, 'Raw data:', data); } } } } } catch (streamError) { console.error('Stream processing error:', streamError); throw streamError; } } catch (error) { console.error('Error:', error); botMessageDiv.textContent = '抱歉,发生错误。'; botMessageDiv.classList.remove('typing'); cursor.remove(); } finally { messageInput.disabled = false; submitBtn.disabled = false; messageInput.focus(); } }); function addMessage(text, sender) { const messageDiv = document.createElement('div'); messageDiv.className = `message ${sender}-message`; messageDiv.textContent = text; chatMessages.appendChild(messageDiv); chatMessages.scrollTop = chatMessages.scrollHeight; } </script> </body> </html> 所有文件 .env 存储了APi-keyindex.html 前端代码server.js 后段代码 总结尽可能的多学习一些知识,或许以后用不到,关注我每天练习一个小demo。
node.js+html调用ChatGPTApi实现Ai网站demo(带源码)由讯客互联软件开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“node.js+html调用ChatGPTApi实现Ai网站demo(带源码)”
上一篇
              netcorehttps配置
下一篇
              Ubuntu终端的常用快捷键