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

网站首页 > 文章精选 正文

创新就是这么简单支持Openai最新模型:请申请使用自己的API聊天

balukai 2025-01-11 10:25:04 文章精选 18 ℃

手机桌面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>

Tags:

最近发表
标签列表