网站首页 > 文章精选 正文
手机桌面API申请地址:
https://gptgod.online/#/session/1bblrz7nhw3yc10lfm3sf9sqw
手机桌面使用请保存下面二维码,使用微信还是浏览器都可以打开、输入自己的API聊天。
手机桌面开源代码↓
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenAI Chat Desktop</title>
<style>
/* 重置一些基础样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background: linear-gradient(to right, #6a11cb, #2575fc);
display: flex;
flex-direction: column;
align-items: center;
height: 100vh;
color: white;
overflow: hidden; /* 防止超出屏幕时出现滚动条 */
transition: background 0.3s ease;
}
/* 顶部工具栏 */
.header {
width: 100%;
padding: 10px 20px;
background: rgba(0, 0, 0, 0.6);
display: flex;
justify-content: space-between;
align-items: center;
position: fixed;
top: 0;
left: 0;
border-radius: 0 0 10px 10px;
}
.header h1 {
font-size: 18px; /* 调整字体大小 */
font-weight: bold;
letter-spacing: 1px;
margin-right: 10px;
}
.header-right{
display: flex;
align-items: center;
}
/*工具箱按钮*/
.tools-button {
background: none;
border: none;
color: white;
font-size: 24px;
cursor: pointer;
padding: 5px;
margin-right: 10px;
}
.full-screen-button {
background: none;
border: none;
color: white;
font-size: 24px;
cursor: pointer;
padding: 5px;
}
.tools-button:focus , .full-screen-button:focus{
outline: none;
}
.model-select-container {
position: relative;
}
.model-select-button {
background: none;
border: none;
color: white;
font-size: 24px;
cursor: pointer;
padding: 5px;
margin-right: 10px;
}
.model-select-button:focus {
outline: none;
}
/*模型选择列表*/
.model-select {
position: absolute;
top: 100%;
right: 0;
display: none;
background: rgba(0, 0, 0, 0.8); /* 设置背景颜色 */
border-radius: 5px;
padding: 5px;
z-index: 1000;
}
.model-select.active {
display: block;
}
.model-select select{
background: rgba(255, 255, 255, 0.1);
border: none;
color: white;
font-size: 14px;
padding: 5px;
}
.model-select select:focus{
outline: none;
}
/*工具箱*/
.tools {
display: none; /* 初始状态隐藏 */
position: absolute;
top: 60px; /* 调整工具箱的位置,位于标题下方 */
left: 0;
z-index: 1000;
background: rgba(0, 0, 0, 0.8); /* 设置背景颜色 */
padding: 10px;
border-radius: 0 0 10px 0;
flex-direction: column;
align-items: flex-start;
}
.tools.active {
display: flex; /* 当工具箱被激活时显示 */
}
.tools input, .tools select , .tools button{
padding: 10px;
margin-bottom: 10px;
background: rgba(255, 255, 255, 0.1);
border: none;
border-radius: 5px;
color: white;
font-size: 14px;
cursor: pointer;
}
.tools input:focus, .tools select:focus,.tools button:focus {
outline: none; /* 去除焦点时的轮廓 */
}
.tools label {
margin-bottom: 5px;
font-size: 14px;
color: #ddd;
display: block; /* 使 label 独占一行 */
}
.tools .option-group{
margin-bottom:10px;
display: flex;
flex-direction: column;
align-items: flex-start;
}
.tools .option-group input[type="radio"]{
margin-right: 5px;
margin-bottom: 0;
}
.color-options {
display: flex;
flex-wrap: wrap; /* 允许颜色选项换行 */
gap: 5px;
margin-bottom: 10px;
}
.color-option {
width: 25px;
height: 25px;
border-radius: 50%;
cursor: pointer;
border: 2px solid transparent;
transition: border-color 0.3s ease;
}
.color-option.selected{
border-color: white;
}
/* 主容器 */
.main-container {
display: flex;
flex-direction: column;
align-items: center;
width: 90%;
max-width: 500px;
margin-top: 80px;
padding: 10px;
background: rgba(255, 255, 255, 0.1);
border-radius: 15px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
flex: 1; /* 使容器占用剩余空间 */
overflow-y: auto;
color: var(--text-color, white);
}
/* 聊天框 */
.chat-box {
width: 100%;
background: rgba(255, 255, 255, 0.2);
border-radius: 10px;
padding: 20px;
margin-top: 20px;
overflow-y: auto; /* 内容超出时允许滚动 */
color: var(--text-color, black);
flex: 1; /* 使聊天框占用剩余空间 */
position: relative;
}
.chat-box .message {
margin-bottom: 10px;
padding: 10px;
border-radius: 5px;
background: white;
word-wrap: break-word;
white-space: pre-line;
position: relative;
transition: background 0.3s ease;
color: var(--text-color, black);
}
.chat-box .message.user {
text-align: right;
background: #28a745;
color: var(--text-color, white);
}
.input-area {
width: 100%;
padding: 10px;
display: flex;
align-items: center;
position: relative; /* 为了绝对定位按钮 */
}
/* 输入框 */
.input-area input {
padding: 12px;
width: calc(100% - 60px); /* 减去按钮的宽度 */
border-radius: 10px;
border: none;
font-size: 16px;
background: rgba(255, 255, 255, 0.1);
color: white;
margin-right:10px;
}
/* 发送按钮 */
.input-area button {
padding: 12px 15px;
border-radius: 10px;
border: none;
font-size: 16px;
background: #28a745;
color: white;
cursor: pointer;
}
/*消息操作按钮*/
.message-actions {
position: absolute;
top: 5px;
right: 5px;
display: none;
gap: 5px;
}
.chat-box .message:hover .message-actions{
display: flex;
}
.message-actions button {
background: transparent;
border: none;
font-size: 14px;
cursor: pointer;
color:#888;
}
.message-actions button:hover{
color: #444;
}
.chat-history-container {
max-height: 200px;
overflow-y: auto;
margin-bottom: 10px;
border: 1px solid #ccc;
padding: 10px;
background-color: #333;
border-radius: 5px;
}
.chat-history-item{
padding:5px;
border-bottom: 1px solid #555;
cursor:pointer;
display: flex;
justify-content: space-between;
align-items: center;
}
.chat-history-item span{
flex-grow: 1;
}
.chat-history-item:last-child{
border-bottom: none;
}
.chat-history-item:hover {
background-color: #555;
}
.chat-history-item button {
background: transparent;
border: none;
font-size: 14px;
cursor: pointer;
color:#888;
padding: 0;
}
.chat-history-item button:hover {
color:#444
}
.full-screen-button{
display:flex;
align-items: center;
justify-content: center;
}
</style>
</head>
<body>
<!-- 顶部工具栏 -->
<div class="header">
<button class="tools-button" onclick="toggleTools()">?</button>
<h1>https://gptgod.online</h1>
<div class="header-right">
<div class="model-select-container">
<button class="model-select-button" onclick="toggleModelSelect()">?</button>
<div class="model-select" id="model-select">
<select id="model-select-dropdown">
</select>
</div>
</div>
<button class="full-screen-button" onclick="toggleFullScreen()">
<span id="fullscreen-icon"> ?</span>
</button>
</div>
</div>
<div class="tools" id="tools">
<label for="api-key">API 密钥:</label>
<input type="text" id="api-key" placeholder="请输入 API Key" />
<div class="option-group">
<label>记忆组:</label>
<input type="radio" id="memory-20" name="memory-size" value="20" checked>
<label for="memory-20">20</label>
<input type="radio" id="memory-50" name="memory-size" value="50">
<label for="memory-50">50</label>
<input type="radio" id="memory-500" name="memory-size" value="500">
<label for="memory-500">500</label>
</div>
<label>字体颜色:</label>
<div class="color-options" id="text-color-options">
</div>
<label>主题颜色:</label>
<div class="color-options" id="theme-color-options">
</div>
<button onclick="clearChatHistory()">清空聊天记录</button>
<label>聊天记录:</label>
<div class="chat-history-container" id="chat-history-container">
<!-- Chat history will be displayed here -->
</div>
</div>
<!-- 主容器 -->
<div class="main-container">
<div class="chat-box" id="chat-box">
<!-- Chat messages will appear here -->
</div>
<div class="input-area">
<input type="text" id="api-input" placeholder="输入你的消息" />
<button onclick="submitMessage()">发送</button>
</div>
</div>
<script>
const chatBox = document.getElementById('chat-box');
const body = document.body;
const apiKeyInput = document.getElementById('api-key');
const modelSelectContainer = document.getElementById('model-select');
const modelSelectButton = document.querySelector('.model-select-button');
const modelSelect = document.getElementById('model-select-dropdown');
const fullScreenButton = document.querySelector('.full-screen-button');
const toolsDiv = document.getElementById('tools');
const chatHistoryContainer = document.getElementById('chat-history-container');
const textColorOptions = document.getElementById('text-color-options');
const themeColorOptions = document.getElementById('theme-color-options');
let isTyping = false; // 用于跟踪是否正在逐字输出
let chatHistory = [];
let memorySize = 20; // 默认记忆组大小
// 原生美学颜色预设
const colorPalette = {
'primary': '#264653',
'secondary': '#2a9d8f',
'tertiary': '#e9c46a',
'accent1': '#f4a261',
'accent2': '#e76f51',
'light1':'#f0efeb',
'light2':'#d6ccc2',
'dark1':'#323232',
'dark2':'#0d0d0d',
'gray':'#636e72'
};
function toggleTools() {
toolsDiv.classList.toggle('active');
if(toolsDiv.classList.contains('active')){
loadChatHistory();
}
}
function toggleModelSelect(){
modelSelectContainer.classList.toggle('active');
}
// 全屏功能
function toggleFullScreen() {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
fullScreenButton.querySelector('#fullscreen-icon').textContent = "?";
} else if (document.exitFullscreen) {
document.exitFullscreen();
fullScreenButton.querySelector('#fullscreen-icon').textContent = "?";
}
}
// 初始化颜色选择器
function initColorOptions() {
// 创建字体颜色选项
Object.keys(colorPalette).forEach(colorName => {
const colorOption = document.createElement('div');
colorOption.classList.add('color-option');
colorOption.style.backgroundColor = colorPalette[colorName];
colorOption.addEventListener('click',() => {
selectTextColor(colorPalette[colorName], colorOption);
});
textColorOptions.appendChild(colorOption);
})
// 创建主题颜色选项
Object.keys(colorPalette).forEach(colorName => {
const colorOption = document.createElement('div');
colorOption.classList.add('color-option');
colorOption.style.backgroundColor = colorPalette[colorName];
colorOption.addEventListener('click',() => {
selectThemeColor(colorPalette[colorName], colorOption);
});
themeColorOptions.appendChild(colorOption);
});
}
// 选择字体颜色
function selectTextColor(color, selectedOption) {
document.querySelectorAll('#text-color-options .color-option').forEach(option => {
option.classList.remove('selected');
});
selectedOption.classList.add('selected');
document.documentElement.style.setProperty('--text-color', color);
localStorage.setItem('textColor', color);
}
// 选择主题颜色
function selectThemeColor(color, selectedOption) {
document.querySelectorAll('#theme-color-options .color-option').forEach(option => {
option.classList.remove('selected');
});
selectedOption.classList.add('selected');
body.style.background = `linear-gradient(to right, ${color}, #2575fc)`;
localStorage.setItem('themeColor', body.style.background);
}
// 加载上次选择的颜色
function loadStoredColor(){
const textColor = localStorage.getItem('textColor');
const themeColor = localStorage.getItem('themeColor');
if (textColor){
document.documentElement.style.setProperty('--text-color', textColor);
let storedTextColor = Array.from(textColorOptions.children).find(option => option.style.backgroundColor === textColor);
if (storedTextColor){
storedTextColor.classList.add('selected');
}
}
if(themeColor){
body.style.background = themeColor;
let storedThemeColor = Array.from(themeColorOptions.children).find(option => option.style.backgroundColor === themeColor.match(/rgb\((.*?)\)/)[0]);
if(storedThemeColor){
storedThemeColor.classList.add('selected');
}
}
}
// 更新记忆组大小
function updateMemorySize(){
const selectedMemory = document.querySelector('input[name="memory-size"]:checked');
if(selectedMemory){
memorySize = parseInt(selectedMemory.value,10);
}
}
// 加载聊天记录
function loadChatHistory(){
const storedHistory = localStorage.getItem('chatHistory');
chatHistory = storedHistory ? JSON.parse(storedHistory) : [];
chatHistoryContainer.innerHTML = '';
chatHistory.forEach((history,index) => {
const item = document.createElement('div');
item.classList.add('chat-history-item');
const span = document.createElement('span');
span.textContent = `会话 ${index + 1}: ${history.messages.length} 条消息`;
item.appendChild(span);
const deleteButton = document.createElement('button');
deleteButton.textContent = 'X';
deleteButton.addEventListener('click', (e) => deleteHistoryItem(e,index));
item.appendChild(deleteButton);
item.addEventListener('click', (e) => {
if (e.target !== deleteButton) {
loadSession(history.messages);
}
});
chatHistoryContainer.appendChild(item);
})
}
// 删除聊天记录项
function deleteHistoryItem(e,index){
e.stopPropagation();
chatHistory.splice(index, 1); // 从数组中删除
localStorage.setItem('chatHistory', JSON.stringify(chatHistory));
loadChatHistory();
}
//加载选中的聊天记录会话
function loadSession(messages){
chatBox.innerHTML = '';
messages.forEach(message => {
addMessage(message.content, message.isUser,true);
});
toggleTools();
}
// 保存聊天记录
function saveChatHistory() {
const currentChat = Array.from(chatBox.querySelectorAll('.message')).map(messageDiv => ({
content: messageDiv.innerText,
isUser: messageDiv.classList.contains('user')
}));
if (currentChat.length > 0) {
chatHistory.push({
messages: currentChat
});
// 限制聊天记录组数
if (chatHistory.length > 10) {
chatHistory.shift(); // 移除最早的记录
}
localStorage.setItem('chatHistory', JSON.stringify(chatHistory));
}
}
function clearChatHistory() {
localStorage.removeItem('chatHistory');
chatHistory = [];
chatHistoryContainer.innerHTML = '';
chatBox.innerHTML = ''; // 清空聊天窗口
}
// 添加模型列表函数
function addModelOptions(models) {
modelSelect.innerHTML = ''; // 清空之前的选项
models.forEach(model => {
const option = document.createElement('option');
option.value = model.id;
option.text = model.id;
modelSelect.appendChild(option);
});
}
// 获取模型列表
function fetchModels() {
const apiKey = apiKeyInput.value; // 获取 API key
if (!apiKey) {
alert('请提供你的API Key!');
return;
}
const url = `https://api.gptgod.online/v1/models`;
const headers = {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
};
fetch(url, {
method: 'GET',
headers: headers,
})
.then(response => response.json())
.then(data => {
console.log(data.data)
addModelOptions(data.data); // 添加模型到下拉列表
})
.catch(error => {
console.error('Error fetching models:', error);
});
}
// 在页面加载时获取模型列表
window.onload = function() {
apiKeyInput.addEventListener('change',fetchModels);
window.addEventListener('beforeunload',saveChatHistory);
document.querySelectorAll('input[name="memory-size"]').forEach(radio => {
radio.addEventListener('change',updateMemorySize);
});
initColorOptions();
loadStoredColor();
};
function addMessage(content, isUser = false, isHistory = false) {
const messageDiv = document.createElement('div');
messageDiv.classList.add('message');
if (isUser) {
messageDiv.classList.add('user');
}
messageDiv.innerText = content;
//添加操作按钮
if(!isHistory){
const actionsDiv = document.createElement('div');
actionsDiv.classList.add('message-actions');
const copyButton = document.createElement('button');
copyButton.textContent = '复制';
copyButton.addEventListener('click', () => copyMessage(content));
const deleteButton = document.createElement('button');
deleteButton.textContent = '删除';
deleteButton.addEventListener('click', () => deleteMessage(messageDiv));
const repeatButton = document.createElement('button');
repeatButton.textContent = '重复';
repeatButton.addEventListener('click',() => repeatMessage(content));
actionsDiv.appendChild(copyButton);
actionsDiv.appendChild(deleteButton);
actionsDiv.appendChild(repeatButton);
messageDiv.appendChild(actionsDiv);
}
chatBox.appendChild(messageDiv);
chatBox.scrollTop = chatBox.scrollHeight;
}
//逐字输出消息
async function addMessageWithTyping(content, isUser = false) {
if (isTyping) return; // 如果正在逐字输出,则不启动新的输出过程
isTyping = true;
const messageDiv = document.createElement('div');
messageDiv.classList.add('message');
if (isUser) {
messageDiv.classList.add('user');
}
chatBox.appendChild(messageDiv);
chatBox.scrollTop = chatBox.scrollHeight;
for (const char of content) {
messageDiv.innerText += char;
chatBox.scrollTop = chatBox.scrollHeight;
await new Promise(resolve => setTimeout(resolve, 15)); // 调整打字速度
}
// 添加操作按钮
const actionsDiv = document.createElement('div');
actionsDiv.classList.add('message-actions');
const copyButton = document.createElement('button');
copyButton.textContent = '复制';
copyButton.addEventListener('click', () => copyMessage(content));
const deleteButton = document.createElement('button');
deleteButton.textContent = '删除';
deleteButton.addEventListener('click', () => deleteMessage(messageDiv));
const repeatButton = document.createElement('button');
repeatButton.textContent = '重复';
repeatButton.addEventListener('click',() => repeatMessage(content));
actionsDiv.appendChild(copyButton);
actionsDiv.appendChild(deleteButton);
actionsDiv.appendChild(repeatButton);
messageDiv.appendChild(actionsDiv);
isTyping = false;
}
async function submitMessage() {
const apiKey = apiKeyInput.value;
const model = modelSelect.value;
const message = document.getElementById('api-input').value;
if (!apiKey || !message || !model) {
alert('请提供你的API Key,消息内容和选择一个模型!');
return;
}
addMessage(message, true);
const storedApiKey = localStorage.getItem('apiKeys')? JSON.parse(localStorage.getItem('apiKeys')) : {};
localStorage.setItem('apiKeys',JSON.stringify(storedApiKey));
const url = `https://api.gptgod.online/v1/chat/completions`;
const headers = {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
};
const payload = {
model: model,
messages: [{ role: 'user', content: message }]
};
try {
const response = await fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(payload)
});
if (!response.ok) {
const errorData = await response.json(); // 解析错误响应
const errorMessage = errorData.error.message || 'Failed to fetch response.';
addMessage('Error: ' + errorMessage, false);
return;
}
const data = await response.json();
const reply = data.choices[0].message.content;
addMessageWithTyping(reply);
} catch (error) {
console.error('Error:', error);
addMessage('Error: 无法获取响应.', false);
}
document.getElementById('api-input').value = ''; // 清空输入框
}
// 复制消息
function copyMessage(text){
navigator.clipboard.writeText(text)
.then(() => {
alert('消息已复制到剪贴板!');
}).catch(err => {
console.error('Failed to copy text: ', err);
});
}
// 删除消息
function deleteMessage(messageDiv) {
messageDiv.remove();
}
//重复消息
function repeatMessage(content){
submitMessage(content);
}
</script>
</body>
</html>
- 上一篇: vue3实现一个无缝衔接、滚动平滑的列表自动横滚屏效果
- 下一篇: 无需Telnet修改光猫桥接模式
猜你喜欢
- 2025-01-11 响应式网页中的高度设计,你认真的吗?
- 2025-01-11 六类食物让你的胸型更完美
- 2025-01-11 11款好看的 Checkbox 切换开关样式 附带原码哦
- 2025-01-11 孕妇孕期患水肿的饮食调理
- 2025-01-11 面试遇到 性能优化 必答的 9 个点,加分!
- 2025-01-11 女性补血食谱 美颜鸡蛋汤女性补血食谱
- 2025-01-11 强迫症的福音,一键去除腾讯爱奇艺优酷等视频网站的LOGO水印
- 2025-01-11 jQuery slideToggle() 方法用法详解
- 2025-01-11 看看新郎壮阳秘方
- 2025-01-11 谷物营养滋润女人的秀发谷物营养滋润女人
- 04-23关于linux coreutils/sort.c源码的延展思考最小堆为什么不用自旋
- 04-23一文精通如何使用二叉树
- 04-23二叉树(Binary Tree)
- 04-23数据结构入门:树(Tree)详细介绍
- 04-23数据结构错题收录(六)
- 04-23Kubernetes原理深度解析:万字图文全总结!
- 04-23一站式速查知识总结,助您轻松驾驭容器编排技术(水平扩展控制)
- 04-23kubectl常用删除命令
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 计算机网络的拓扑结构是指() (45)
- 稳压管的稳压区是工作在什么区 (45)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)