程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

谷歌最新AI聊天手机桌面:请使用自己的谷歌语言模型API聊天

balukai 2025-01-04 17:01:22 文章精选 8 ℃


谷歌AI手机桌面运行代码平台:https://codepen.io/ttcssxep-the-selector/pen/ByBQqQo可以复制以下的代码,在这个平台上面去运行,输入你的谷歌官方模型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>

body {

font-family: sans-serif;

margin: 0;

padding: 0;

background-color: #f0f0f0;

display: flex;

justify-content: center;

align-items: center;

min-height: 100vh;

transition: background-color 0.5s ease;

}

.chat-container {

position: fixed;

bottom: 0;

right: 0;

background-color: #fff;

border-radius: 10px 10px 0 0;

box-shadow: 0 -2px 10px rgba(0,0,0,0.1);

width: 100%;

max-width: 600px;

height: 80vh;

max-height: 800px;

display: flex;

flex-direction: column;

border: 1px solid #ddd;

transition: background-color 0.5s ease, color 0.5s ease;

}

.chat-header {

display: flex;

flex-direction: column;

padding: 15px;

border-bottom: 1px solid #ddd;

background-color: #f9f9f9;

}

.chat-settings {

display: flex;

gap: 10px;

flex-wrap: wrap;

align-items: center;

}

.chat-settings select,

.chat-settings input {

padding: 10px;

border: 1px solid #ccc;

border-radius: 5px;

flex: 1;

min-width: 150px;

}

.chat-buttons {

display: flex;

gap: 10px;

margin-top: 10px;

flex-wrap: wrap;

}

.chat-buttons button {

background-color: #eee;

cursor: pointer;

transition: background-color 0.3s ease;

white-space: nowrap;

border: 1px solid #ddd;

border-radius: 5px;

padding: 10px;

flex: 1;

min-width: 80px;

}

.chat-buttons button:hover {

background-color: #ddd;

}

.chat-messages {

flex-grow: 1;

padding: 15px;

overflow-y: auto;

display: flex;

flex-direction: column;

gap: 15px;

background-color: #fafafa;

height: calc(80vh - 200px); /* 调整高度以适应固定窗口 */

}

.message-container {

display: flex;

align-items: center;

position: relative;

}

.message-container:hover .copy-button {

opacity: 1;

}

.message {

padding: 10px 15px;

border-radius: 20px;

max-width: 75%;

word-wrap: break-word;

transition: background-color 0.3s ease;

white-space: pre-line;

font-size: 1em;

}

.copy-button {

position: absolute;

right: 10px;

top: 50%;

transform: translateY(-50%);

background-color: transparent;

border: none;

cursor: pointer;

font-size: 14px;

opacity: 0;

transition: opacity 0.3s ease;

padding: 5px 10px;

border-radius: 5px;

background-color: #f0f0f0;

}

.copy-button:hover {

background-color: #e0e0e0;

}

.user-message {

background-color: #DCF8C6;

align-self: flex-end;

color: #333;

}

.ai-message {

background-color: #E5E5EA;

align-self: flex-start;

color: #333;

}

.chat-input {

display: flex;

padding: 15px;

border-top: 1px solid #ddd;

background-color: #f9f9f9;

}

.chat-input input {

flex-grow: 1;

border: 1px solid #ccc;

border-radius: 5px;

padding: 10px;

margin-right: 10px;

font-size: 1em;

}

.chat-input button {

background-color: #007bff;

color: white;

border: none;

border-radius: 5px;

padding: 10px 15px;

cursor: pointer;

font-size: 1em;

}

.chat-input button:hover {

background-color: #0056b3;

}

.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: rgba(0, 0, 0, 0.5);

display: none;

align-items: center;

justify-content: center;

z-index: 1000;

}

.color-options, .memory-options, .history-options, .save-chat-overlay {

background-color: #fff;

padding: 25px;

border-radius: 10px;

display: flex;

flex-wrap: wrap;

gap: 15px;

max-width: 400px;

width: 90%;

}

.color-option {

width: 35px;

height: 35px;

border-radius: 50%;

cursor: pointer;

border: 1px solid #ddd;

transition: border 0.3s ease;

}

.color-option:hover {

border: 2px solid #999;

}

.memory-options, .history-options {

flex-direction: column;

}

.history-item {

display: flex;

justify-content: space-between;

align-items: center;

padding: 10px;

border-bottom: 1px solid #ddd;

}

.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;

}

.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 #ccc;

border-radius: 5px;

width: 100%;

margin-bottom: 15px;

font-size: 1em;

}

.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;

}

.save-chat-overlay button:hover {

background-color: #218838;

}

@media (max-width: 600px) {

.chat-container {

width: 100%;

height: 80vh;

border-radius: 10px 10px 0 0;

max-width: none;

max-height: none;

}

}

</style>

</head>

<body>

<div class="chat-container">

<div class="chat-header">

<div class="chat-settings">

<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>

</select>

<input type="text" id="apiKeyInput" placeholder="输入API Key">

</div>

<div class="chat-buttons">

<button id="changeColorButton">主题</button>

<button id="memoryButton">记忆</button>

<button id="chatHistoryButton">聊天记录</button>

<button id="clearChatButton">清空</button>

</div>

</div>

<div class="chat-messages" id="chatMessages">

<!-- 消息将动态添加到这里 -->

</div>

<div class="chat-input">

<input type="text" id="messageInput" placeholder="输入消息...">

<button id="sendButton">发送</button>

</div>

</div>

<div id="errorMessage" class="error-message" style="display: none;"></div>

<!-- 主题选择 -->

<div id="colorOverlay" class="overlay">

<div class="color-options" id="colorOptions">

<!-- 颜色选项将动态添加到这里 -->

</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">保存记忆</button>

<button id="clearMemoryButton">清除记忆</button>

</div>

</div>

<!-- 聊天记录 -->

<div id="chatHistoryOverlay" class="overlay">

<div class="history-options">

<h3>聊天记录</h3>

<div id="historyList">

<!-- 历史记录项将动态添加到这里 -->

</div>

<button id="closeHistoryButton">关闭</button>

</div>

</div>

<!-- 保存聊天 -->

<div id="saveChatOverlay" class="overlay">

<div class="save-chat-overlay">

<h3>保存当前聊天</h3>

<input type="text" id="chatTitleInput" placeholder="输入聊天标题">

<button id="saveChatButton">保存</button>

<button id="cancelSaveChatButton">取消</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 changeColorButton = document.getElementById('changeColorButton');

const clearChatButton = document.getElementById('clearChatButton');

const chatHistoryButton = document.getElementById('chatHistoryButton');

const colorOverlay = document.getElementById('colorOverlay');

const colorOptions = document.getElementById('colorOptions');

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 backgroundColors = [

'#f0f0f0', '#e0e0e0', '#d0d0d0', '#c0c0c0', '#b0b0b0',

'#a0a0a0', '#909090', '#808080', '#707070', '#606060',

'#f8bbd0','#f06292','#e91e63', '#9c27b0',

'#673ab7','#3f51b5','#2196f3', '#03a9f4',

'#00bcd4', '#009688', '#4caf50', '#8bc34a'

];

const textColors = [

'#333', '#444', '#555', '#666', '#777',

'#888', '#999', '#aaa', '#bbb', '#ccc',

'#000', '#1a237e','#4a148c','#0d47a1',

'#01579b','#004d40','#1b5e20','#33691e',

'#bf360c', '#d84315', '#ff6f00',

'#ff8f00'

];

const chatContainer = document.querySelector('.chat-container');

let currentBackgroundColorIndex = 0;

let currentTextColorIndex = 0;

let chatHistory = []; // 当前聊天会话的消息

let memorySize = localStorage.getItem('memorySize') || '10';

// 初始化API Key

document.addEventListener('DOMContentLoaded', () => {

const savedApiKey = localStorage.getItem('apiKey');

if (savedApiKey) {

apiKeyInput.value = savedApiKey;

}

loadChatHistory();

});

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';

});

changeColorButton.addEventListener('click', () => {

colorOverlay.style.display = 'flex';

});

colorOverlay.addEventListener('click', (event) => {

if(event.target === colorOverlay) {

colorOverlay.style.display = 'none';

}

});

function changeColorTheme(bgColor, textColor) {

document.body.style.backgroundColor = bgColor;

chatContainer.style.backgroundColor = bgColor;

chatContainer.style.color = textColor;

}

function createColorOptions() {

colorOptions.innerHTML = '';

for (let i = 0; i < backgroundColors.length; i++) {

const colorDiv = document.createElement('div');

colorDiv.classList.add('color-option');

colorDiv.style.backgroundColor = backgroundColors[i];

colorDiv.addEventListener('click', () => {

currentBackgroundColorIndex = i;

currentTextColorIndex = i;

changeColorTheme(backgroundColors[currentBackgroundColorIndex], textColors[currentTextColorIndex]);

colorOverlay.style.display = 'none';

});

colorOptions.appendChild(colorDiv);

}

}

createColorOptions();

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;

activeSession.messages.forEach(entry => {

appendMessage(entry.sender, entry.text, false);

});

updateActiveSession(activeSession.id);

}

}

}

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);

chatHistory.push({ sender: 'user', text: message });

saveChatHistory();

messageInput.value = '';

try {

let aiResponse = await sendToAI(message, apiKey, selectedModel, chatHistory);

aiResponse = aiResponse.replace(/\*/g, ''); // 去除星号

typeWriter(aiResponse, 'ai');

chatHistory.push({ sender: 'ai', text: aiResponse });

saveChatHistory();

} catch (error) {

showError(`AI回复失败: ${error.message}`);

appendMessage('ai', "AI回复失败,请稍后重试", true);

}

});

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.textContent = '加载';

loadButton.addEventListener('click', () => {

loadSession(session.id);

chatHistoryOverlay.style.display = 'none';

});

itemDiv.appendChild(loadButton);

const deleteButton = document.createElement('button');

deleteButton.textContent = '删除';

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);

});

}

}

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 = '';

}

}

function appendMessage(sender, text, shouldScroll = true) {

const messageContainer = document.createElement('div');

messageContainer.classList.add('message-container');

const messageDiv = document.createElement('div');

messageDiv.classList.add('message');

messageDiv.classList.add(sender + '-message');

messageDiv.innerText = text;

messageContainer.appendChild(messageDiv);

const copyButton = document.createElement('button');

copyButton.classList.add('copy-button');

copyButton.innerText = '复制';

copyButton.addEventListener('click', () => {

copyToClipboard(text);

});

messageContainer.appendChild(copyButton);

chatMessages.appendChild(messageContainer);

if (shouldScroll) {

chatMessages.scrollTo({

top: chatMessages.scrollHeight,

behavior: 'smooth'

});

}

}

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');

const messageDiv = document.createElement('div');

messageDiv.classList.add('message');

messageDiv.classList.add(sender + '-message');

messageContainer.appendChild(messageDiv);

const copyButton = document.createElement('button');

copyButton.classList.add('copy-button');

copyButton.innerText = '复制';

copyButton.addEventListener('click', () => {

copyToClipboard(text);

});

messageContainer.appendChild(copyButton);

chatMessages.appendChild(messageContainer);

// 滚动到最新消息

chatMessages.scrollTo({

top: chatMessages.scrollHeight,

behavior: 'smooth'

});

let i = 0;

const intervalId = setInterval(() => {

if (i < text.length) {

messageDiv.textContent += text.charAt(i);

i++;

chatMessages.scrollTo({

top: chatMessages.scrollHeight,

behavior: 'smooth'

});

} else {

clearInterval(intervalId);

}

}, 30);

}

function showError(message) {

errorMessageDiv.textContent = message;

errorMessageDiv.style.display = 'block';

}

function hideError() {

errorMessageDiv.style.display = 'none';

errorMessageDiv.textContent = "";

}

// 允许按 Enter 键发送消息

messageInput.addEventListener('keydown', (event) => {

if (event.key === 'Enter') {

sendButton.click();

}

});

</script>

</body>

</html>

Tags:

最近发表
标签列表