> 技术文档 > 给自己网站增加一个免费的AI助手,纯HTML_自己的网站系统如何加入ai助手

给自己网站增加一个免费的AI助手,纯HTML_自己的网站系统如何加入ai助手


助手效果图

看完这篇文章,你将免费拥有你自己的Ai助手,全程干货,先到先得
给自己网站增加一个免费的AI助手,纯HTML_自己的网站系统如何加入ai助手

获取免费的AI大模型接口

访问这个地址 生成key https://openrouter.ai/mistralai/mistral-small-3.2-24b-instruct:free/api
或者调用其他的免费大模型,这个根据自己的需求更改,要先注册这个网站
给自己网站增加一个免费的AI助手,纯HTML_自己的网站系统如何加入ai助手

修改默认的参数

最主要的就是你申请生成的key
给自己网站增加一个免费的AI助手,纯HTML_自己的网站系统如何加入ai助手

助手源码

纯HTML的源码,嘎嘎够劲

<!DOCTYPE html><html lang=\"zh-CN\"><head> <meta charset=\"UTF-8\"> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"> <title></title> <style> body { font-family: \'Arial\', sans-serif; margin: 0; padding: 0; height: 100vh; user-select: none; overflow: hidden; } #chat-container { position: fixed; bottom: 20px; right: 20px; width: 300px; height: 400px; background-color: white; border-radius: 10px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); display: flex; flex-direction: column; overflow: hidden; z-index: 1000; resize: both; min-width: 300px; min-height: 400px; transition: transform 0.2s ease, opacity 0.2s ease; transform-origin: bottom right; } #chat-container.minimized { transform: scale(0); opacity: 0; pointer-events: none; } #chat-header { background-color: #4a6bdf; color: white; padding: 12px 15px; cursor: move; display: flex; justify-content: space-between; align-items: center; } #chat-title { font-weight: bold; font-size: 16px; } #minimize-btn, #restore-btn { background: none; border: none; color: white; font-size: 18px; cursor: pointer; padding: 0; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; } #minimized-chat { position: fixed; width: 50px; height: 50px; border-radius: 10px; background-color: #4a6bdf; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); z-index: 1000; display: none; transition: transform 0.1s ease; } #minimized-chat:active { transform: scale(0.95); } #restore-btn { position: absolute; width: 100%; height: 100%; font-size: 24px; display: flex; align-items: center; justify-content: center; cursor: move; pointer-events: auto; } #chat-messages { flex: 1; padding: 15px; overflow-y: auto; background-color: #f9f9f9; } .message { margin-bottom: 12px; max-width: 80%; padding: 8px 12px; border-radius: 12px; line-height: 1.4; word-wrap: break-word; } .user-message { background-color: #e3effd; margin-left: auto; border-bottom-right-radius: 4px; } .ai-message { background-color: white; margin-right: auto; border-bottom-left-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } #chat-input-area { display: flex; padding: 10px; border-top: 1px solid #eee; background-color: white; } #chat-input { flex: 1; padding: 10px; border: 1px solid #ddd; border-radius: 20px; outline: none; resize: none; height: 40px; max-height: 100px; font-family: inherit; } #send-btn { margin-left: 10px; padding: 0 15px; background-color: #4a6bdf; color: white; border: none; border-radius: 20px; cursor: pointer; transition: background-color 0.2s; } #send-btn.stop { background-color: #ff4d4d; } #send-btn:hover { background-color: #3a5bcf; } #send-btn.stop:hover { background-color: #e63c3c; } .typing-indicator { display: inline-block; margin-left: 5px; } .typing-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background-color: #999; margin-right: 3px; animation: typingAnimation 1.4s infinite ease-in-out; } .typing-dot:nth-child(1) { animation-delay: 0s; } .typing-dot:nth-child(2) { animation-delay: 0.2s; } .typing-dot:nth-child(3) { animation-delay: 0.4s; } @keyframes typingAnimation { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-5px); } } .stopped-message { color: #888; font-style: italic; } </style></head><body> <div id=\"chat-container\"> <div id=\"chat-header\"> <div id=\"chat-title\">AI助手</div> <button id=\"minimize-btn\"></button> </div> <div id=\"chat-messages\"></div> <div id=\"chat-input-area\"> <textarea id=\"chat-input\" placeholder=\"输入消息...\" rows=\"1\"></textarea> <button id=\"send-btn\">发送</button> </div> </div> <div id=\"minimized-chat\"> <button id=\"restore-btn\">+</button> </div> <script> // 获取DOM元素 const chatContainer = document.getElementById(\'chat-container\'); const chatHeader = document.getElementById(\'chat-header\'); const minimizedChat = document.getElementById(\'minimized-chat\'); const minimizeBtn = document.getElementById(\'minimize-btn\'); const restoreBtn = document.getElementById(\'restore-btn\'); const chatInput = document.getElementById(\'chat-input\'); const sendBtn = document.getElementById(\'send-btn\'); const chatMessages = document.getElementById(\'chat-messages\'); // 全局变量 let isDragging = false; let isMinimizedDragging = false; let offsetX, offsetY; let startX, startY; let restoreBtnClicked = false; let abortController = null; // 用于中止fetch请求 let isWaitingForResponse = false; // 是否正在等待响应 let isTypingEffectActive = false; // 是否正在打字效果中 let typingTimeoutId = null; // 打字效果的timeout ID // 限制元素在窗口范围内 function constrainToWindow(element, x, y) { const rect = element.getBoundingClientRect(); const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; const maxX = windowWidth - rect.width; const maxY = windowHeight - rect.height; x = Math.max(0, Math.min(x, maxX)); y = Math.max(0, Math.min(y, maxY)); return { x, y }; } // 主窗口拖动功能 chatHeader.addEventListener(\'mousedown\', (e) => { if (e.target.id !== \'chat-header\' && e.target.id !== \'chat-title\') return; isDragging = true; startX = e.clientX; startY = e.clientY; const rect = chatContainer.getBoundingClientRect(); offsetX = startX - rect.left; offsetY = startY - rect.top; chatContainer.style.cursor = \'grabbing\'; chatContainer.style.transition = \'none\'; e.preventDefault(); }); // 恢复按钮拖动功能 restoreBtn.addEventListener(\'mousedown\', (e) => { isMinimizedDragging = true; restoreBtnClicked = false; startX = e.clientX; startY = e.clientY; const rect = minimizedChat.getBoundingClientRect(); offsetX = startX - rect.left; offsetY = startY - rect.top; minimizedChat.style.cursor = \'grabbing\'; minimizedChat.style.transition = \'none\'; e.preventDefault(); e.stopPropagation(); }); // 恢复按钮点击功能 restoreBtn.addEventListener(\'dblclick\', (e) => { if (!isMinimizedDragging && !restoreBtnClicked) { restoreBtnClicked = true; restoreChatWindow(); } e.stopPropagation(); }); document.addEventListener(\'mousemove\', (e) => { if (isDragging) { let x = e.clientX - offsetX; let y = e.clientY - offsetY; const constrained = constrainToWindow(chatContainer, x, y); x = constrained.x; y = constrained.y; chatContainer.style.left = `${x}px`; chatContainer.style.top = `${y}px`; chatContainer.style.right = \'auto\'; chatContainer.style.bottom = \'auto\'; } if (isMinimizedDragging) { let x = e.clientX - offsetX; let y = e.clientY - offsetY; const constrained = constrainToWindow(minimizedChat, x, y); x = constrained.x; y = constrained.y; minimizedChat.style.left = `${x}px`; minimizedChat.style.top = `${y}px`; minimizedChat.style.right = \'auto\'; minimizedChat.style.bottom = \'auto\'; } }); document.addEventListener(\'mouseup\', () => { if (isDragging) { isDragging = false; chatContainer.style.cursor = \'default\'; chatContainer.style.transition = \'transform 0.2s ease, opacity 0.2s ease\'; } if (isMinimizedDragging) { isMinimizedDragging = false; minimizedChat.style.cursor = \'move\'; minimizedChat.style.transition = \'transform 0.1s ease\'; } }); // 缩小/恢复功能 minimizeBtn.addEventListener(\'click\', (e) => { e.stopPropagation(); const rect = chatContainer.getBoundingClientRect(); minimizedChat.style.left = `${rect.left}px`; minimizedChat.style.top = `${rect.top}px`; minimizedChat.style.right = \'auto\'; minimizedChat.style.bottom = \'auto\'; const constrained = constrainToWindow( minimizedChat,  parseFloat(minimizedChat.style.left || 0), parseFloat(minimizedChat.style.top || 0) ); minimizedChat.style.left = `${constrained.x}px`; minimizedChat.style.top = `${constrained.y}px`; chatContainer.classList.add(\'minimized\'); setTimeout(() => { minimizedChat.style.display = \'block\'; }, 200); }); function restoreChatWindow() { chatContainer.style.left = \'auto\'; chatContainer.style.top = \'auto\'; chatContainer.style.right = \'20px\'; chatContainer.style.bottom = \'20px\'; chatContainer.classList.remove(\'minimized\'); minimizedChat.style.display = \'none\'; } // 聊天功能 chatInput.addEventListener(\'input\', function() { this.style.height = \'auto\'; this.style.height = (this.scrollHeight > 100 ? 100 : this.scrollHeight) + \'px\'; }); function sendMessage() { const message = chatInput.value.trim(); if (!message) return; addMessage(message, \'user\'); chatInput.value = \'\'; chatInput.style.height = \'40px\'; // 改变按钮状态 setSendButtonState(\'stop\'); const typingId = showTypingIndicator(); simulateAIResponse(message, typingId); } function stopRequest() { if (abortController) { abortController.abort(); abortController = null; } if (isTypingEffectActive) { clearTimeout(typingTimeoutId); isTypingEffectActive = false; // 添加停止提示 const stoppedDiv = document.createElement(\'div\'); stoppedDiv.className = \'message ai-message stopped-message\'; stoppedDiv.textContent = \'已停止生成回复\'; chatMessages.appendChild(stoppedDiv); chatMessages.scrollTop = chatMessages.scrollHeight; } setSendButtonState(\'send\'); isWaitingForResponse = false; // 移除正在输入指示器 const typingElements = document.querySelectorAll(\'[id^=\"typing-\"]\'); typingElements.forEach(el => el.remove()); } function setSendButtonState(state) { if (state === \'stop\') { sendBtn.textContent = \'停止\'; sendBtn.classList.add(\'stop\'); sendBtn.removeEventListener(\'click\', sendMessage); sendBtn.addEventListener(\'click\', stopRequest); isWaitingForResponse = true; } else { sendBtn.textContent = \'发送\'; sendBtn.classList.remove(\'stop\'); sendBtn.removeEventListener(\'click\', stopRequest); sendBtn.addEventListener(\'click\', sendMessage); isWaitingForResponse = false; } } chatInput.addEventListener(\'keydown\', (e) => { if (e.key === \'Enter\' && !e.shiftKey) { e.preventDefault(); if (!isWaitingForResponse) {  sendMessage(); } } }); // 初始化按钮事件 sendBtn.addEventListener(\'click\', sendMessage); function addMessage(text, sender) { const messageDiv = document.createElement(\'div\'); messageDiv.className = `message ${sender}-message`; messageDiv.textContent = text; chatMessages.appendChild(messageDiv); chatMessages.scrollTop = chatMessages.scrollHeight; } function showTypingIndicator() { const typingDiv = document.createElement(\'div\'); typingDiv.className = \'message ai-message\'; typingDiv.id = \'typing-\' + Date.now(); const typingText = document.createElement(\'span\'); typingText.textContent = \'YiLin:\'; const typingDots = document.createElement(\'span\'); typingDots.className = \'typing-indicator\'; for (let i = 0; i < 3; i++) { const dot = document.createElement(\'span\'); dot.className = \'typing-dot\'; typingDots.appendChild(dot); } typingDiv.appendChild(typingText); typingDiv.appendChild(typingDots); chatMessages.appendChild(typingDiv); chatMessages.scrollTop = chatMessages.scrollHeight; return typingDiv.id; } function removeTypingIndicator(id) { const typingElement = document.getElementById(id); if (typingElement) { typingElement.remove(); } } async function simulateAIResponse(userMessage, typingId) { abortController = new AbortController(); try { const response = await fetch(\"https://openrouter.ai/api/v1/chat/completions\", {  method: \"POST\",  headers: { \"Authorization\": \"Bearer sk-or-v1-xxxxxxxxxxxx\", \"HTTP-Referer\": \"https://nanwish.love\", \"X-Title\": \"沂霖博客\", \"Content-Type\": \"application/json\"  },  body: JSON.stringify({ \"model\": \"mistralai/mistral-small-3.2-24b-instruct:free\", \"messages\": [ { \"role\": \"user\", \"content\": [  {  \"type\": \"text\",  \"text\": userMessage  } ] } ]  }),  signal: abortController.signal }); const data = await response.json(); removeTypingIndicator(typingId); if (data.choices && data.choices[0].message.content) {  typeWriterEffect(data.choices[0].message.content); } else {  addMessage(\"抱歉,未能获取有效回复\", \'ai\');  setSendButtonState(\'send\'); } } catch (error) { if (error.name !== \'AbortError\') {  removeTypingIndicator(typingId);  addMessage(\"抱歉,发生错误: \" + error.message, \'ai\');  setSendButtonState(\'send\'); } } finally { abortController = null; } } function typeWriterEffect(text) { const messageDiv = document.createElement(\'div\'); messageDiv.className = \'message ai-message\'; chatMessages.appendChild(messageDiv); let i = 0; const speed = 20; isTypingEffectActive = true; function type() { if (i < text.length) {  messageDiv.textContent += text.charAt(i);  i++;  chatMessages.scrollTop = chatMessages.scrollHeight;  typingTimeoutId = setTimeout(type, speed); } else {  isTypingEffectActive = false;  setSendButtonState(\'send\'); } } type(); } // 初始化 window.addEventListener(\'DOMContentLoaded\', () => { minimizedChat.style.display = \'none\'; setTimeout(() => { typeWriterEffect(\"你好!我是沂霖,我可以辅助你使用MarkDown,聊天,查资料!你可以输入问题或指令,我会尽力回答。\"); }, 500); }); // 窗口大小变化时重新限制位置 window.addEventListener(\'resize\', () => { if (!chatContainer.classList.contains(\'minimized\')) { const rect = chatContainer.getBoundingClientRect(); const constrained = constrainToWindow(chatContainer, rect.left, rect.top); chatContainer.style.left = `${constrained.x}px`; chatContainer.style.top = `${constrained.y}px`; } if (minimizedChat.style.display === \'block\') { const rect = minimizedChat.getBoundingClientRect(); const constrained = constrainToWindow(minimizedChat, rect.left, rect.top); minimizedChat.style.left = `${constrained.x}px`; minimizedChat.style.top = `${constrained.y}px`; } }); </script></body></html>

把这个嵌入到你的网站页面 就可以实现站点助手了

给自己网站增加一个免费的AI助手,纯HTML_自己的网站系统如何加入ai助手