谷歌大语言模型最新升级手机桌面:请使用自己的谷歌官方API聊天
yuyutoo 2024-12-26 17:32 2 浏览 0 评论
使用谷歌AI大语言模型可以保存下面二维码在微信还是浏览器打开,输入自己的谷歌官方模型API就可以聊天了。
谷歌官方API申请:
https://aistudio.google.com/app/apikey
谷歌AI手机桌面开源代码↓
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI 聊天</title>
<style>
/* 定义CSS变量 */
:root {
--background-color: #f0f0f0;
--text-color: #333333;
--primary-color: #007bff;
--secondary-color: #6c757d;
--border-color: #ddd;
--input-background-color: #ffffff;
--button-background-color: #007bff;
--button-text-color: #ffffff;
--button-hover-background-color: #0056b3;
--user-message-background: #DCF8C6;
--ai-message-background: #E5E5EA;
--chat-background-color: #fafafa;
--topbar-background-color: #f9f9f9;
--overlay-background-color: rgba(0, 0, 0, 0.5);
--shadow-color: rgba(0, 0, 0, 0.1);
--action-button-size: 16px;
--action-button-color: #555;
--action-button-hover-color: var(--button-hover-background-color);
}
body {
font-family: sans-serif;
margin: 0;
padding: 0;
background-color: var(--background-color);
color: var(--text-color);
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
transition: background-color 0.5s ease, color 0.5s ease;
}
.top-settings {
display: flex;
justify-content: space-between;
width: 100%;
max-width: 600px;
padding: 15px;
background-color: var(--topbar-background-color);
border-bottom: 1px solid var(--border-color);
box-sizing: border-box;
}
.top-settings .settings-group {
flex: 1;
display: flex;
gap: 10px;
flex-wrap: wrap;
align-items: center;
}
.top-settings .fullscreen-button {
background-color: var(--button-background-color);
color: var(--button-text-color);
cursor: pointer;
transition: background-color 0.3s ease;
white-space: nowrap;
border: 1px solid var(--border-color);
border-radius: 5px;
padding: 10px;
min-width: 50px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2em;
}
.top-settings .fullscreen-button:hover {
background-color: var(--button-hover-background-color);
}
.top-settings select,
.top-settings input {
padding: 10px;
border: 1px solid var(--border-color);
border-radius: 5px;
flex: 1;
min-width: 150px;
box-sizing: border-box;
background-color: var(--input-background-color);
color: var(--text-color);
}
.chat-container {
flex-grow: 1;
width: 100%;
max-width: 600px;
display: flex;
flex-direction: column;
border: 1px solid var(--border-color);
transition: background-color 0.5s ease, color 0.5s ease;
background-color: var(--input-background-color);
box-shadow: 0 2px 10px var(--shadow-color);
margin-bottom: 0;
}
.chat-buttons {
display: flex;
gap: 10px;
padding: 15px;
background-color: var(--topbar-background-color);
border-bottom: 1px solid var(--border-color);
flex-wrap: wrap;
box-sizing: border-box;
}
.chat-buttons button {
background-color: var(--button-background-color);
color: var(--button-text-color);
cursor: pointer;
transition: background-color 0.3s ease;
white-space: nowrap;
border: 1px solid var(--border-color);
border-radius: 5px;
padding: 10px;
flex: 1;
min-width: 80px;
display: flex;
align-items: center;
justify-content: center;
gap: 5px;
}
.chat-buttons button:hover {
background-color: var(--button-hover-background-color);
}
.chat-messages {
flex-grow: 1;
padding: 15px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 15px;
background-color: var(--chat-background-color);
}
.message-container {
display: flex;
align-items: flex-start;
position: relative;
}
.message {
padding: 10px 15px;
border-radius: 20px;
max-width: 75%;
word-wrap: break-word;
transition: background-color 0.3s ease;
white-space: pre-wrap; /* 支持多行和公式 */
font-size: 1em;
}
.copy-button,
.delete-button,
.repeat-button {
background: none;
border: none;
cursor: pointer;
font-size: var(--action-button-size);
color: var(--action-button-color);
margin-left: 5px;
display: none; /* 默认隐藏 */
}
.copy-button:hover,
.delete-button:hover,
.repeat-button:hover {
color: var(--action-button-hover-color);
}
.message-container:hover .copy-button,
.message-container:hover .delete-button,
.message-container:hover .repeat-button {
display: inline; /* 鼠标悬停时显示按钮 */
}
.user-message {
background-color: var(--user-message-background);
align-self: flex-end;
color: var(--text-color);
position: relative;
}
.ai-message {
background-color: var(--ai-message-background);
align-self: flex-start;
color: var(--text-color);
position: relative;
}
.chat-input {
display: flex;
padding: 15px;
border-top: 1px solid var(--border-color);
background-color: var(--topbar-background-color);
position: sticky;
bottom: 0;
box-sizing: border-box;
}
.chat-input input {
flex-grow: 1;
border: 1px solid var(--border-color);
border-radius: 5px;
padding: 10px;
margin-right: 10px;
font-size: 1em;
background-color: var(--input-background-color);
color: var(--text-color);
}
.chat-input button {
background-color: var(--button-background-color);
color: var(--button-text-color);
border: none;
border-radius: 5px;
padding: 10px 15px;
cursor: pointer;
font-size: 1em;
display: flex;
align-items: center;
gap: 5px;
}
.chat-input button:hover {
background-color: var(--button-hover-background-color);
}
.error-message {
color: red;
font-size: 0.9em;
margin-top: 5px;
text-align: center;
}
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: var(--overlay-background-color);
display: none;
align-items: center;
justify-content: center;
z-index: 1000;
}
.theme-options,
.memory-options,
.history-options,
.save-chat-overlay {
background-color: var(--input-background-color);
padding: 25px;
border-radius: 10px;
display: flex;
flex-wrap: wrap;
gap: 15px;
max-width: 400px;
width: 90%;
}
.theme-option {
width: 100%;
padding: 10px;
border-radius: 5px;
cursor: pointer;
color: var(--text-color);
background-color: var(--button-background-color);
text-align: center;
transition: background-color 0.3s ease;
}
.theme-option:hover {
background-color: var(--button-hover-background-color);
}
.memory-options,
.history-options {
flex-direction: column;
}
.history-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
border-bottom: 1px solid var(--border-color);
}
.history-item:last-child {
border-bottom: none;
}
.history-item button {
background-color: #ff4d4d;
color: white;
border: none;
border-radius: 5px;
padding: 7px 12px;
cursor: pointer;
display: flex;
align-items: center;
gap: 5px;
}
.history-item button:hover {
background-color: #e60000;
}
.history-item span {
flex-grow: 1;
margin-right: 10px;
word-break: break-word;
}
.save-chat-overlay input {
padding: 10px;
border: 1px solid var(--border-color);
border-radius: 5px;
width: 100%;
margin-bottom: 15px;
font-size: 1em;
background-color: var(--input-background-color);
color: var(--text-color);
}
.save-chat-overlay button {
background-color: #28a745;
color: white;
border: none;
border-radius: 5px;
padding: 10px 15px;
cursor: pointer;
margin-bottom: 10px;
font-size: 1em;
display: flex;
align-items: center;
gap: 5px;
}
.save-chat-overlay button:hover {
background-color: #218838;
}
@media (max-width: 600px) {
.top-settings {
flex-direction: column;
}
.top-settings .settings-group {
flex-direction: column;
gap: 5px;
}
.top-settings select,
.top-settings input {
min-width: auto;
}
.chat-container {
width: 100%;
border-radius: 0;
max-width: none;
}
}
</style>
<!-- Font Awesome 图标库 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- MathJax 支持数学公式 -->
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
</head>
<body>
<div class="top-settings">
<div class="settings-group">
<select id="modelSelect">
<option value="gemini-pro">gemini-pro</option>
<option value="gemini-exp-1114">gemini-exp-1114</option>
<option value="learnlm-1.5-pro-experimental">learnlm-1.5-pro-experimental</option>
<option value="gemini-exp-1206">gemini-exp-1206</option>
<option value="gemini-2.0-flash-exp">gemini-2.0-flash-exp</option>
<option value="gemini-exp-1121">gemini-exp-1121</option>
<option value="gemini-2.0-flash-thinking-exp-1219">gemini-2.0-flash-thinking-exp-1219</option>
</select>
<input type="text" id="apiKeyInput" placeholder="输入API Key">
</div>
<button class="fullscreen-button" id="fullscreenButton"><i class="fas fa-expand"></i></button>
</div>
<div class="chat-container">
<div class="chat-buttons">
<button id="changeThemeButton"><i class="fas fa-paint-brush"></i> 主题</button>
<button id="memoryButton"><i class="fas fa-memory"></i> 记忆</button>
<button id="chatHistoryButton"><i class="fas fa-history"></i> 聊天记录</button>
<button id="clearChatButton"><i class="fas fa-trash-alt"></i> 清空</button>
</div>
<div class="chat-messages" id="chatMessages">
<!-- 消息将动态添加到这里 -->
</div>
<div class="chat-input">
<input type="text" id="messageInput" placeholder="输入消息...">
<button id="sendButton"><i class="fas fa-paper-plane"></i> 发送</button>
</div>
</div>
<div id="errorMessage" class="error-message" style="display: none;"></div>
<!-- 主题选择 -->
<div id="themeOverlay" class="overlay">
<div class="theme-options" id="themeOptions">
<!-- 主题选项将动态添加到这里 -->
</div>
</div>
<!-- 记忆设置 -->
<div id="memoryOverlay" class="overlay">
<div class="memory-options">
<select id="memorySizeSelect">
<option value="10">保存最近10组对话</option>
<option value="50">保存最近50组对话</option>
<option value="100">保存最近100组对话</option>
</select>
<button id="saveMemoryButton"><i class="fas fa-save"></i> 保存记忆</button>
<button id="clearMemoryButton"><i class="fas fa-eraser"></i> 清除记忆</button>
</div>
</div>
<!-- 聊天记录 -->
<div id="chatHistoryOverlay" class="overlay">
<div class="history-options">
<h3>聊天记录</h3>
<div id="historyList">
<!-- 历史记录项将动态添加到这里 -->
</div>
<button id="closeHistoryButton"><i class="fas fa-times"></i> 关闭</button>
</div>
</div>
<!-- 保存聊天 -->
<div id="saveChatOverlay" class="overlay">
<div class="save-chat-overlay">
<h3>保存当前聊天</h3>
<input type="text" id="chatTitleInput" placeholder="输入聊天标题">
<button id="saveChatButton"><i class="fas fa-save"></i> 保存</button>
<button id="cancelSaveChatButton"><i class="fas fa-times"></i> 取消</button>
</div>
</div>
<script type="module">
import { GoogleGenerativeAI } from "https://esm.run/@google/generative-ai";
const modelSelect = document.getElementById('modelSelect');
const apiKeyInput = document.getElementById('apiKeyInput');
const messageInput = document.getElementById('messageInput');
const sendButton = document.getElementById('sendButton');
const chatMessages = document.getElementById('chatMessages');
const errorMessageDiv = document.getElementById('errorMessage');
const changeThemeButton = document.getElementById('changeThemeButton');
const clearChatButton = document.getElementById('clearChatButton');
const chatHistoryButton = document.getElementById('chatHistoryButton');
const themeOverlay = document.getElementById('themeOverlay');
const themeOptions = document.getElementById('themeOptions');
const memoryButton = document.getElementById('memoryButton');
const memoryOverlay = document.getElementById('memoryOverlay');
const memorySizeSelect = document.getElementById('memorySizeSelect');
const saveMemoryButton = document.getElementById('saveMemoryButton');
const clearMemoryButton = document.getElementById('clearMemoryButton');
const chatHistoryOverlay = document.getElementById('chatHistoryOverlay');
const historyList = document.getElementById('historyList');
const closeHistoryButton = document.getElementById('closeHistoryButton');
const saveChatOverlay = document.getElementById('saveChatOverlay');
const chatTitleInput = document.getElementById('chatTitleInput');
const saveChatButton = document.getElementById('saveChatButton');
const cancelSaveChatButton = document.getElementById('cancelSaveChatButton');
const fullscreenButton = document.getElementById('fullscreenButton');
const themes = [
{
name: "经典蓝",
properties: {
'--background-color': '#f0f8ff',
'--text-color': '#333333',
'--primary-color': '#007bff',
'--button-background-color': '#007bff',
'--button-hover-background-color': '#0056b3',
'--user-message-background': '#cce5ff',
'--ai-message-background': '#e2e3e5',
'--chat-background-color': '#ffffff',
'--topbar-background-color': '#f8f9fa',
}
},
{
name: "清新绿",
properties: {
'--background-color': '#e8f5e9',
'--text-color': '#2e7d32',
'--primary-color': '#43a047',
'--button-background-color': '#43a047',
'--button-hover-background-color': '#2e7d32',
'--user-message-background': '#a5d6a7',
'--ai-message-background': '#c8e6c9',
'--chat-background-color': '#ffffff',
'--topbar-background-color': '#e8f5e9',
}
},
{
name: "暖阳橙",
properties: {
'--background-color': '#fff3e0',
'--text-color': '#ef6c00',
'--primary-color': '#fb8c00',
'--button-background-color': '#fb8c00',
'--button-hover-background-color': '#ef6c00',
'--user-message-background': '#ffe0b2',
'--ai-message-background': '#ffcc80',
'--chat-background-color': '#ffffff',
'--topbar-background-color': '#ffe0b2',
}
},
{
name: "优雅紫",
properties: {
'--background-color': '#f3e5f5',
'--text-color': '#6a1b9a',
'--primary-color': '#9c27b0',
'--button-background-color': '#9c27b0',
'--button-hover-background-color': '#6a1b9a',
'--user-message-background': '#ce93d8',
'--ai-message-background': '#e1bee7',
'--chat-background-color': '#ffffff',
'--topbar-background-color': '#f3e5f5',
}
},
{
name: "深空灰",
properties: {
'--background-color': '#eceff1',
'--text-color': '#37474f',
'--primary-color': '#607d8b',
'--button-background-color': '#607d8b',
'--button-hover-background-color': '#455a64',
'--user-message-background': '#cfd8dc',
'--ai-message-background': '#b0bec5',
'--chat-background-color': '#ffffff',
'--topbar-background-color': '#eceff1',
}
},
{
name: "淡雅粉",
properties: {
'--background-color': '#fce4ec',
'--text-color': '#ad1457',
'--primary-color': '#ec407a',
'--button-background-color': '#ec407a',
'--button-hover-background-color': '#ad1457',
'--user-message-background': '#f8bbd0',
'--ai-message-background': '#f48fb1',
'--chat-background-color': '#ffffff',
'--topbar-background-color': '#fce4ec',
}
},
{
name: "活力黄",
properties: {
'--background-color': '#fffde7',
'--text-color': '#f9a825',
'--primary-color': '#fdd835',
'--button-background-color': '#fdd835',
'--button-hover-background-color': '#f9a825',
'--user-message-background': '#fff9c4',
'--ai-message-background': '#fff59d',
'--chat-background-color': '#ffffff',
'--topbar-background-color': '#fffde7',
}
},
{
name: "海洋蓝",
properties: {
'--background-color': '#e0f7fa',
'--text-color': '#006064',
'--primary-color': '#00bcd4',
'--button-background-color': '#00bcd4',
'--button-hover-background-color': '#006064',
'--user-message-background': '#b2ebf2',
'--ai-message-background': '#80deea',
'--chat-background-color': '#ffffff',
'--topbar-background-color': '#e0f7fa',
}
},
{
name: "森林绿",
properties: {
'--background-color': '#e8f5e9',
'--text-color': '#1b5e20',
'--primary-color': '#4caf50',
'--button-background-color': '#4caf50',
'--button-hover-background-color': '#388e3c',
'--user-message-background': '#a5d6a7',
'--ai-message-background': '#c8e6c9',
'--chat-background-color': '#ffffff',
'--topbar-background-color': '#e8f5e9',
}
},
{
name: "炫酷黑",
properties: {
'--background-color': '#212121',
'--text-color': '#ffffff',
'--primary-color': '#424242',
'--button-background-color': '#424242',
'--button-hover-background-color': '#616161',
'--user-message-background': '#424242',
'--ai-message-background': '#616161',
'--chat-background-color': '#303030',
'--topbar-background-color': '#212121',
}
},
];
let isFullscreen = false;
let chatHistory = [];
let memorySize = localStorage.getItem('memorySize') || '10';
// 初始化API Key和主题
document.addEventListener('DOMContentLoaded', () => {
const savedApiKey = localStorage.getItem('apiKey');
if (savedApiKey) {
apiKeyInput.value = savedApiKey;
}
loadChatHistory();
createThemeOptions();
// 应用保存的主题(如果有)
const savedTheme = localStorage.getItem('selectedTheme');
if (savedTheme) {
applyTheme(JSON.parse(savedTheme));
}
});
// 处理全屏按钮点击事件
fullscreenButton.addEventListener('click', toggleFullscreen);
function toggleFullscreen() {
if (!isFullscreen) {
openFullscreen();
} else {
closeFullscreen();
}
}
function openFullscreen() {
const element = document.documentElement; // 获取文档根元素
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.mozRequestFullScreen) { /* Firefox */
element.mozRequestFullScreen();
} else if (element.webkitRequestFullscreen) { /* Chrome, Safari & Opera */
element.webkitRequestFullscreen();
} else if (element.msRequestFullscreen) { /* IE/Edge */
element.msRequestFullscreen();
}
isFullscreen = true;
fullscreenButton.innerHTML = '<i class="fas fa-compress"></i>';
}
function closeFullscreen() {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) { /* Firefox */
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) { /* Chrome, Safari and Opera */
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) { /* IE/Edge */
document.msExitFullscreen();
}
isFullscreen = false;
fullscreenButton.innerHTML = '<i class="fas fa-expand"></i>';
}
// 处理记忆按钮点击事件
memoryButton.addEventListener('click', () => {
memoryOverlay.style.display = 'flex';
});
memoryOverlay.addEventListener('click', (event) => {
if (event.target === memoryOverlay) {
memoryOverlay.style.display = 'none';
}
});
saveMemoryButton.addEventListener('click', () => {
memorySize = memorySizeSelect.value;
localStorage.setItem('memorySize', memorySize);
memoryOverlay.style.display = 'none';
showError(`记忆大小已设置为保存最近${memorySize}组对话。`);
setTimeout(hideError, 3000);
});
clearMemoryButton.addEventListener('click', () => {
if (confirm("确定要清除所有聊天记录吗?")) {
localStorage.removeItem('chatSessions');
localStorage.removeItem('apiKey');
showError("所有聊天记录和API Key已清除。");
setTimeout(hideError, 3000);
chatHistory = [];
chatMessages.innerHTML = '';
apiKeyInput.value = '';
}
memoryOverlay.style.display = 'none';
});
// 处理主题按钮点击事件
changeThemeButton.addEventListener('click', () => {
themeOverlay.style.display = 'flex';
});
themeOverlay.addEventListener('click', (event) => {
if (event.target === themeOverlay) {
themeOverlay.style.display = 'none';
}
});
// 创建主题选项
function createThemeOptions() {
themeOptions.innerHTML = '';
themes.forEach((theme, index) => {
const themeDiv = document.createElement('div');
themeDiv.classList.add('theme-option');
themeDiv.textContent = theme.name;
themeDiv.addEventListener('click', () => {
applyTheme(theme.properties);
themeOverlay.style.display = 'none';
});
themeOptions.appendChild(themeDiv);
});
}
// 应用主题
function applyTheme(themeProperties) {
for (let key in themeProperties) {
document.documentElement.style.setProperty(key, themeProperties[key]);
}
localStorage.setItem('selectedTheme', JSON.stringify(themeProperties));
}
// 处理聊天历史按钮点击事件
chatHistoryButton.addEventListener('click', () => {
loadChatSessions();
chatHistoryOverlay.style.display = 'flex';
});
chatHistoryOverlay.addEventListener('click', (event) => {
if (event.target === chatHistoryOverlay) {
chatHistoryOverlay.style.display = 'none';
}
});
closeHistoryButton.addEventListener('click', () => {
chatHistoryOverlay.style.display = 'none';
});
// 处理保存聊天覆盖层点击事件
saveChatOverlay.addEventListener('click', (event) => {
if (event.target === saveChatOverlay) {
saveChatOverlay.style.display = 'none';
}
});
// 保存聊天
saveChatButton.addEventListener('click', () => {
const title = chatTitleInput.value.trim();
if (!title) {
alert('请为聊天会话输入一个标题。');
return;
}
saveCurrentChatSession(title);
chatTitleInput.value = '';
saveChatOverlay.style.display = 'none';
showError("聊天会话已保存。");
setTimeout(hideError, 3000);
});
// 取消保存聊天
cancelSaveChatButton.addEventListener('click', () => {
chatTitleInput.value = '';
saveChatOverlay.style.display = 'none';
});
// 清空聊天
clearChatButton.addEventListener('click', () => {
if (chatHistory.length === 0) {
alert("当前聊天记录已为空。");
return;
}
if (confirm("是否保存当前聊天记录?")) {
saveChatOverlay.style.display = 'flex';
} else {
chatMessages.innerHTML = '';
chatHistory = [];
showError("聊天记录已清空。");
setTimeout(hideError, 3000);
}
});
// 加载聊天历史
function loadChatHistory() {
const storedSessions = localStorage.getItem('chatSessions');
if (storedSessions) {
const sessions = JSON.parse(storedSessions);
const activeSession = sessions.find(session => session.isActive);
if (activeSession) {
chatHistory = activeSession.messages;
chatMessages.innerHTML = ''; // 清空现有消息
activeSession.messages.forEach(entry => {
if (entry.sender === 'ai') {
appendMessage(entry.sender, entry.text, false, false); // 不要类型写入
} else {
appendMessage(entry.sender, entry.text, false, false); // 不要类型写入
}
});
// 处理数学公式渲染
MathJax.typesetPromise();
scrollToBottom();
}
}
}
// 发送消息按钮事件
sendButton.addEventListener('click', async () => {
const message = messageInput.value.trim();
let apiKey = apiKeyInput.value.trim();
const selectedModel = modelSelect.value;
if (!apiKey) {
showError("请先输入 API Key。");
return;
}
if (!message) {
showError("请输入消息。");
return;
}
hideError();
// 保存API Key到localStorage
localStorage.setItem('apiKey', apiKey);
appendMessage('user', message, true, true);
chatHistory.push({ sender: 'user', text: message });
saveChatHistory();
messageInput.value = '';
try {
let aiResponse = await sendToAI(message, apiKey, selectedModel, chatHistory);
aiResponse = aiResponse.replace(/\*/g, ''); // 去除星号
aiResponse = formatMath(aiResponse); // 格式化数学公式
typeWriter(aiResponse, 'ai');
chatHistory.push({ sender: 'ai', text: aiResponse });
saveChatHistory();
} catch (error) {
showError(`AI回复失败: ${error.message}`);
appendMessage('ai', "AI回复失败,请稍后重试", true, false);
}
});
// 发送消息到AI
async function sendToAI(message, apiKey, model, history) {
try {
const genAI = new GoogleGenerativeAI(apiKey);
const generativeModel = genAI.getGenerativeModel({ model: model });
const prompt = history.map(item => `${item.sender}: ${item.text}`).join('\n') + `\nuser: ${message}`;
const result = await generativeModel.generateContent(prompt);
if (result && result.response && result.response.text) {
return result.response.text();
} else {
throw new Error("无效的 AI 回复");
}
} catch (error) {
console.error("Error during AI response:", error);
throw error;
}
}
// 保存聊天历史
function saveChatHistory() {
let sessions = JSON.parse(localStorage.getItem('chatSessions')) || [];
const activeSessionIndex = sessions.findIndex(session => session.isActive);
if (activeSessionIndex !== -1) {
sessions[activeSessionIndex].messages = chatHistory;
} else {
const newSession = {
id: Date.now(),
title: `未命名会话 ${sessions.length + 1}`,
messages: chatHistory,
isActive: true
};
sessions.push(newSession);
}
if (sessions.length > parseInt(memorySize, 10)) {
sessions = sessions.slice(-parseInt(memorySize, 10));
}
localStorage.setItem('chatSessions', JSON.stringify(sessions));
}
// 保存当前聊天会话
function saveCurrentChatSession(title) {
let sessions = JSON.parse(localStorage.getItem('chatSessions')) || [];
sessions.forEach(session => session.isActive = false);
const newSession = {
id: Date.now(),
title: title,
messages: chatHistory,
isActive: true
};
sessions.push(newSession);
if (sessions.length > parseInt(memorySize, 10)) {
sessions = sessions.slice(-parseInt(memorySize, 10));
}
localStorage.setItem('chatSessions', JSON.stringify(sessions));
}
// 加载聊天会话
function loadChatSessions() {
historyList.innerHTML = '';
const sessions = JSON.parse(localStorage.getItem('chatSessions')) || [];
if (sessions.length === 0) {
historyList.innerHTML = '<p>暂无聊天记录。</p>';
return;
}
sessions.forEach(session => {
const itemDiv = document.createElement('div');
itemDiv.classList.add('history-item');
const titleSpan = document.createElement('span');
titleSpan.textContent = session.title;
itemDiv.appendChild(titleSpan);
const loadButton = document.createElement('button');
loadButton.innerHTML = '<i class="fas fa-download"></i> 加载';
loadButton.title = '加载';
loadButton.addEventListener('click', () => {
loadSession(session.id);
chatHistoryOverlay.style.display = 'none';
});
itemDiv.appendChild(loadButton);
const deleteButton = document.createElement('button');
deleteButton.innerHTML = '<i class="fas fa-trash"></i> 删除';
deleteButton.title = '删除';
deleteButton.addEventListener('click', () => {
if (confirm(`确定要删除 "${session.title}" 吗?`)) {
deleteSession(session.id);
loadChatSessions();
}
});
itemDiv.appendChild(deleteButton);
historyList.appendChild(itemDiv);
});
}
// 加载特定会话
function loadSession(id) {
const sessions = JSON.parse(localStorage.getItem('chatSessions')) || [];
const session = sessions.find(s => s.id === id);
if (session) {
sessions.forEach(s => s.isActive = false);
session.isActive = true;
localStorage.setItem('chatSessions', JSON.stringify(sessions));
chatHistory = session.messages;
chatMessages.innerHTML = '';
chatHistory.forEach(entry => {
appendMessage(entry.sender, entry.text, false, false);
});
// 处理数学公式渲染
MathJax.typesetPromise();
scrollToBottom();
}
}
// 删除特定会话
function deleteSession(id) {
let sessions = JSON.parse(localStorage.getItem('chatSessions')) || [];
sessions = sessions.filter(s => s.id !== id);
localStorage.setItem('chatSessions', JSON.stringify(sessions));
const activeSession = sessions.find(s => s.isActive);
if (!activeSession) {
chatHistory = [];
chatMessages.innerHTML = '';
}
}
// 格式化数学公式为MathJax可识别的格式
function formatMath(text) {
// 确保数学公式用$符号包裹,用户应使用LaTeX语法
return text;
}
// 添加消息
function appendMessage(sender, text, shouldScroll = true, isTyping = false) {
const messageContainer = document.createElement('div');
messageContainer.classList.add('message-container', `${sender}-message`);
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', `${sender}-message`);
if (isTyping) {
messageDiv.textContent = text; // 初始为全部文本(AI会通过打字效果重新填充)
} else {
messageDiv.innerHTML = text; // 使用innerHTML以支持MathJax
// 触发MathJax渲染
MathJax.typesetPromise();
}
messageContainer.appendChild(messageDiv);
// 添加功能按钮
const copyButton = document.createElement('button');
copyButton.classList.add('copy-button');
copyButton.innerHTML = '<i class="fas fa-copy"></i>';
copyButton.title = '复制';
copyButton.addEventListener('click', () => {
copyToClipboard(text);
});
messageContainer.appendChild(copyButton);
const deleteButton = document.createElement('button');
deleteButton.classList.add('delete-button');
deleteButton.innerHTML = '<i class="fas fa-trash"></i>';
deleteButton.title = '删除';
deleteButton.addEventListener('click', () => {
if (confirm("确定要删除这条消息吗?")) {
messageContainer.remove();
// 从chatHistory中移除该消息
chatHistory = chatHistory.filter(msg => !(msg.sender === sender && msg.text === text));
saveChatHistory();
}
});
messageContainer.appendChild(deleteButton);
const repeatButton = document.createElement('button');
repeatButton.classList.add('repeat-button');
repeatButton.innerHTML = '<i class="fas fa-redo"></i>';
repeatButton.title = '重复';
repeatButton.addEventListener('click', () => {
if (sender === 'user') {
messageInput.value = text;
messageInput.focus();
} else if (sender === 'ai') {
// 对于AI消息,可以选择重新发送最后一条用户消息
const lastUserMessage = [...chatHistory].reverse().find(msg => msg.sender === 'user');
if (lastUserMessage) {
messageInput.value = lastUserMessage.text;
messageInput.focus();
}
}
});
messageContainer.appendChild(repeatButton);
chatMessages.appendChild(messageContainer);
if (shouldScroll) {
scrollToBottom();
}
}
// 复制到剪贴板
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
alert('文本已复制');
}).catch(err => {
console.error('复制失败', err);
alert('复制失败,请稍后重试');
});
}
// 打字效果
function typeWriter(text, sender) {
const messageContainer = document.createElement('div');
messageContainer.classList.add('message-container', `${sender}-message`);
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', `${sender}-message`);
messageContainer.appendChild(messageDiv);
// 添加功能按钮
const copyButton = document.createElement('button');
copyButton.classList.add('copy-button');
copyButton.innerHTML = '<i class="fas fa-copy"></i>';
copyButton.title = '复制';
copyButton.addEventListener('click', () => {
copyToClipboard(text);
});
messageContainer.appendChild(copyButton);
const deleteButton = document.createElement('button');
deleteButton.classList.add('delete-button');
deleteButton.innerHTML = '<i class="fas fa-trash"></i>';
deleteButton.title = '删除';
deleteButton.addEventListener('click', () => {
if (confirm("确定要删除这条消息吗?")) {
messageContainer.remove();
// 从chatHistory中移除该消息
chatHistory = chatHistory.filter(msg => !(msg.sender === sender && msg.text === text));
saveChatHistory();
}
});
messageContainer.appendChild(deleteButton);
const repeatButton = document.createElement('button');
repeatButton.classList.add('repeat-button');
repeatButton.innerHTML = '<i class="fas fa-redo"></i>';
repeatButton.title = '重复';
repeatButton.addEventListener('click', () => {
if (sender === 'user') {
messageInput.value = text;
messageInput.focus();
} else if (sender === 'ai') {
// 对于AI消息,可以选择重新发送最后一条用户消息
const lastUserMessage = [...chatHistory].reverse().find(msg => msg.sender === 'user');
if (lastUserMessage) {
messageInput.value = lastUserMessage.text;
messageInput.focus();
}
}
});
messageContainer.appendChild(repeatButton);
chatMessages.appendChild(messageContainer);
// 初始为空
let displayedText = '';
let i = 0;
const intervalId = setInterval(() => {
if (i < text.length) {
displayedText += text.charAt(i);
messageDiv.textContent = displayedText;
i++;
scrollToBottom();
} else {
clearInterval(intervalId);
// 完成后渲染数学公式
MathJax.typesetPromise([messageDiv]);
}
}, 30);
}
// 显示错误信息
function showError(message) {
errorMessageDiv.textContent = message;
errorMessageDiv.style.display = 'block';
}
// 隐藏错误信息
function hideError() {
errorMessageDiv.style.display = 'none';
errorMessageDiv.textContent = "";
}
// 自动滚动到聊天底部
function scrollToBottom() {
chatMessages.scrollTo({
top: chatMessages.scrollHeight,
behavior: 'smooth'
});
}
// 允许按 Enter 键发送消息
messageInput.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
sendButton.click();
}
});
</script>
</body>
</html>
相关推荐
- 史上最全的浏览器兼容性问题和解决方案
-
微信ID:WEB_wysj(点击关注)◎◎◎◎◎◎◎◎◎一┳═┻︻▄(页底留言开放,欢迎来吐槽)●●●...
-
- 平面设计基础知识_平面设计基础知识实验收获与总结
-
CSS构造颜色,背景与图像1.使用span更好的控制文本中局部区域的文本:文本;2.使用display属性提供区块转变:display:inline(是内联的...
-
2025-02-21 16:01 yuyutoo
- 写作排版简单三步就行-工具篇_作文排版模板
-
和我们工作中日常word排版内部交流不同,这篇教程介绍的写作排版主要是用于“微信公众号、头条号”网络展示。写作展现的是我的思考,排版是让写作在网格上更好地展现。在写作上花费时间是有累积复利优势的,在排...
- 写一个2048的游戏_2048小游戏功能实现
-
1.创建HTML文件1.打开一个文本编辑器,例如Notepad++、SublimeText、VisualStudioCode等。2.将以下HTML代码复制并粘贴到文本编辑器中:html...
- 今天你穿“短袖”了吗?青岛最高23℃!接下来几天气温更刺激……
-
最近的天气暖和得让很多小伙伴们喊“热”!!! 昨天的气温到底升得有多高呢?你家有没有榜上有名?...
- CSS不规则卡片,纯CSS制作优惠券样式,CSS实现锯齿样式
-
之前也有写过CSS优惠券样式《CSS3径向渐变实现优惠券波浪造型》,这次再来温习一遍,并且将更为详细的讲解,从布局到具体样式说明,最后定义CSS变量,自定义主题颜色。布局...
- 你的自我界限够强大吗?_你的自我界限够强大吗英文
-
我的结果:A、该设立新的界限...
- 行内元素与块级元素,以及区别_行内元素和块级元素有什么区别?
-
行内元素与块级元素首先,CSS规范规定,每个元素都有display属性,确定该元素的类型,每个元素都有默认的display值,分别为块级(block)、行内(inline)。块级元素:(以下列举比较常...
-
- 让“成都速度”跑得潇潇洒洒,地上地下共享轨交繁华
-
去年的两会期间,习近平总书记在参加人大会议四川代表团审议时,对治蜀兴川提出了明确要求,指明了前行方向,并带来了“祝四川人民的生活越来越安逸”的美好祝福。又是一年...
-
2025-02-21 16:00 yuyutoo
- 今年国家综合性消防救援队伍计划招录消防员15000名
-
记者24日从应急管理部获悉,国家综合性消防救援队伍2023年消防员招录工作已正式启动。今年共计划招录消防员15000名,其中高校应届毕业生5000名、退役士兵5000名、社会青年5000名。本次招录的...
- 一起盘点最新 Chrome v133 的5大主流特性 ?
-
1.CSS的高级attr()方法CSSattr()函数是CSSLevel5中用于检索DOM元素的属性值并将其用于CSS属性值,类似于var()函数替换自定义属性值的方式。...
- 竞走团体世锦赛5月太仓举行 世界冠军杨家玉担任形象大使
-
style="text-align:center;"data-mce-style="text-align:...
- 学物理能做什么?_学物理能做什么 卢昌海
-
作者:曹则贤中国科学院物理研究所原标题:《物理学:ASourceofPowerforMan》在2006年中央电视台《对话》栏目的某期节目中,主持人问过我一个的问题:“学物理的人,如果日后不...
-
- 你不知道的关于这只眯眼兔的6个小秘密
-
在你们忙着给熊本君做表情包的时候,要知道,最先在网络上引起轰动的可是这只脸上只有两条缝的兔子——兔斯基。今年,它更是迎来了自己的10岁生日。①关于德艺双馨“老艺...
-
2025-02-21 16:00 yuyutoo
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)