百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

谷歌大语言模型最新升级手机桌面:请使用自己的谷歌官方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个小秘密
你不知道的关于这只眯眼兔的6个小秘密

在你们忙着给熊本君做表情包的时候,要知道,最先在网络上引起轰动的可是这只脸上只有两条缝的兔子——兔斯基。今年,它更是迎来了自己的10岁生日。①关于德艺双馨“老艺...

2025-02-21 16:00 yuyutoo

取消回复欢迎 发表评论: