简易的ai对话网站示例,使用gpt-4o-mini模型
需要连接vpn使用
展示图片:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ChatGPT 中文界面</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
height: 100vh;
}
#chat-container {
flex-grow: 1;
padding: 20px;
overflow-y: auto;
background-color: #f5f5f5;
}
#chat-container .message {
margin-bottom: 15px;
}
#chat-container .message.user {
text-align: right;
}
#chat-container .message.user span {
background-color: #0078d7;
color: white;
padding: 8px 12px;
border-radius: 15px;
display: inline-block;
}
#chat-container .message.assistant {
position: relative;
}
#chat-container .message.assistant .markdown-content {
background-color: #e0e0e0;
color: black;
padding: 8px 12px;
border-radius: 15px;
white-space: pre-wrap;
overflow-x: auto;
}
#chat-container .message.assistant .copy-btn {
position: absolute;
top: 5px;
right: 5px;
background: #0078d7;
color: white;
border: none;
padding: 5px 10px;
border-radius: 3px;
cursor: pointer;
}
#chat-container .message.assistant .copy-btn:hover {
background: #005bb5;
}
#input-container {
display: flex;
padding: 10px;
background-color: #ffffff;
border-top: 1px solid #ddd;
}
#input-container input {
flex-grow: 1;
padding: 10px;
font-size: 16px;
border: 1px solid #ddd;
border-radius: 5px;
}
#input-container button {
margin-left: 10px;
padding: 10px 20px;
font-size: 16px;
background-color: #0078d7;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
#input-container button:hover {
background-color: #005bb5;
}
#context-toggle {
position: absolute;
top: 10px;
right: 10px;
background-color: #0078d7;
color: white;
border: none;
padding: 10px;
border-radius: 5px;
cursor: pointer;
}
#context-toggle.active {
background-color: #005bb5;
}
.loading {
font-style: italic;
color: #666;
margin-top: 10px;
animation: blink 1.2s infinite;
}
@keyframes blink {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
</style>
</head>
<body>
<button id="context-toggle">联系上下文:关闭</button>
<div id="chat-container"></div>
<div id="input-container">
<input type="text" id="user-input" placeholder="请输入您的问题..." />
<button onclick="sendMessage()">发送</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
const apiKey = '你的openai api密钥填写在此';
const chatContainer = document.getElementById('chat-container');
const userInput = document.getElementById('user-input');
const contextToggle = document.getElementById('context-toggle');
let contextEnabled = false; // 是否启用上下文
let messages = []; // 保存上下文的消息数组
// 切换上下文功能
contextToggle.addEventListener('click', () => {
contextEnabled = !contextEnabled;
contextToggle.textContent = `联系上下文:${contextEnabled ? '开启' : '关闭'}`;
contextToggle.classList.toggle('active', contextEnabled);
if (!contextEnabled) messages = []; // 如果关闭上下文,清空历史记录
});
async function sendMessage() {
const userMessage = userInput.value.trim();
if (!userMessage) return;
// 显示用户消息
addMessage(userMessage, 'user');
userInput.value = '';
// 保存用户消息到上下文
if (contextEnabled) messages.push({ role: 'user', content: userMessage });
// 显示加载动画
const loadingMessage = document.createElement('div');
loadingMessage.className = 'loading';
loadingMessage.textContent = 'AI 正在思考中...';
chatContainer.appendChild(loadingMessage);
chatContainer.scrollTop = chatContainer.scrollHeight;
try {
// 调用 OpenAI API
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`,
},
body: JSON.stringify({
model: 'gpt-4o-mini',
messages: contextEnabled ? messages : [{ role: 'user', content: userMessage }],
}),
});
if (response.ok) {
const data = await response.json();
const reply = data.choices[0].message.content;
loadingMessage.remove(); // 移除加载动画
addAnimatedMessage(reply, 'assistant');
if (contextEnabled) messages.push({ role: 'assistant', content: reply }); // 保存AI回复到上下文
} else {
const error = await response.json();
loadingMessage.textContent = `错误:${error.error.message}`;
}
} catch (error) {
loadingMessage.textContent = '错误:无法连接到服务器。';
}
}
function addMessage(text, sender) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${sender}`;
if (sender === 'assistant') {
const markdownContent = document.createElement('div');
markdownContent.className = 'markdown-content';
markdownContent.innerHTML = marked.parse(text);
const copyButton = document.createElement('button');
copyButton.className = 'copy-btn';
copyButton.textContent = '复制';
copyButton.onclick = () => copyToClipboard(text);
messageDiv.appendChild(copyButton);
messageDiv.appendChild(markdownContent);
} else {
const messageContent = document.createElement('span');
messageContent.textContent = text;
messageDiv.appendChild(messageContent);
}
chatContainer.appendChild(messageDiv);
chatContainer.scrollTop = chatContainer.scrollHeight;
}
function addAnimatedMessage(text, sender) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${sender}`;
const markdownContent = document.createElement('div');
markdownContent.className = 'markdown-content';
messageDiv.appendChild(markdownContent);
chatContainer.appendChild(messageDiv);
chatContainer.scrollTop = chatContainer.scrollHeight;
let index = 0;
function typeWriter() {
if (index < text.length) {
markdownContent.innerHTML += text[index];
index++;
setTimeout(typeWriter, 30); // 控制逐字输出速度
} else {
markdownContent.innerHTML = marked.parse(text); // 最后格式化 Markdown
}
}
typeWriter();
}
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
alert('内容已复制到剪贴板!');
}).catch(err => {
alert('复制失败:' + err);
});
}
</script>
</body>
</html>