免费GPT,gemini,克劳德!‖日常爆改佬友公益

今天改的是这位: https://linux.do/t/topic/186209?u=stellafortuna
声明:服务作者限定为二级用户可用,本帖不限制,但想使用需获取密码,鼓励大家更加活跃冲二级~
根据原作者的初代demo站源码改的
也是相当方便的
不过改成一坨了:sob:

更新日志

发帖时:目前尝试支持了两个gpt模型,都是可以用的

二十八日凌晨1点:进行一波小更新,目前支持了v1和v2调用,优化了页面显示,支持i18n! 更多细节,请各位佬友自行发现~

29日凌晨1点:重磅更新,继续优化UI,优化暗色模式,添加语言切换选项,添加查询余额功能 新加了一个日期分隔符 最重要的是什么?现在支持所有已知可用模型啦!
演示站稍后更新
30日18点:演示站更新…
31日17点:再次宣布更新~ 该版本修复了查询额度失败的问题,更新了支持模型表,更换了字体,避免需魔法:crystal_ball:的困境,优化部分文案提示,支持复制信息和重新回答(复制手机用不了:sob:) ,现在支持一键清除聊天记录了,添加了一个欢迎信息(请不要试图让他重新回答…)演示站同步更新

我们让老伙计websim来优化一下UI,并免费提供专属域名~
演示站(20240831):https://websim.ai/@Stella/aiduihuawebui

代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>星缘AI助手 - 智能对话体验</title>
    <style>
    :root {
        --primary-color: #4a90e2;
        --secondary-color: #50c878;
        --text-color: #333;
        --background-color: #f6f9fc;
        --chat-background: #ffffff;
        --input-background: #f0f4f8;
        --button-hover: #3a7bd5;
        --shadow-color: rgba(74, 144, 226, 0.1);
        --message-user: linear-gradient(135deg, #4a90e2 0%, #50c878 100%);
        --message-bot: linear-gradient(135deg, #e0e3e8 0%, #c7d2fe 100%);
        --input-border: #d1d9e6;
        --scrollbar-thumb: #c1c1c1;
        --scrollbar-track: #f1f1f1;
    }

    .dark-mode {
        --primary-color: #6a8caf;
        --secondary-color: #68b88e;
        --text-color: #e0e0e0;
        --background-color: #1a1a2e;
        --chat-background: #16213e;
        --input-background: #0f3460;
        --button-hover: #5a72a3;
        --shadow-color: rgba(106, 140, 175, 0.2);
        --message-user: linear-gradient(135deg, #6a8caf 0%, #68b88e 100%);
        --message-bot: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
        --input-border: #2c3e50;
        --scrollbar-thumb: #4a4a4a;
        --scrollbar-track: #2a2a2a;
    }

    * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
    }

    body {
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
        background: var(--background-color);
        color: var(--text-color);
        display: flex;
        justify-content: center;
        align-items: center;
        min-height: 100vh;
        margin: 0;
        padding: 20px;
        transition: all 0.3s ease;
    }

    .chat-container {
        width: 100%;
        max-width: 1000px;
        background-color: var(--chat-background);
        border-radius: 20px;
        box-shadow: 0 10px 50px var(--shadow-color);
        display: flex;
        flex-direction: column;
        overflow: hidden;
    }

    .chat-header {
        padding: 20px;
        background: var(--message-user);
        color: #fff;
        text-align: center;
        font-size: 24px;
        font-weight: 500;
        display: flex;
        justify-content: space-between;
        align-items: center;
    }

    .header-controls {
        display: flex;
        align-items: center;
        gap: 10px;
    }

    #channelSelect, #modelSelect, #languageSelect {
        padding: 8px;
        border-radius: 5px;
        border: 1px solid var(--input-border);
        background-color: var(--input-background);
        color: var(--text-color);
        font-size: 14px;
    }

    .btn {
        background: rgba(255,255,255,0.2);
        border: none;
        color: white;
        font-size: 20px;
        cursor: pointer;
        transition: all 0.3s ease;
        padding: 8px;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
    }

    .btn:hover {
        background: rgba(255,255,255,0.4);
        transform: scale(1.1);
    }

    .chat-messages {
        padding: 30px;
        flex-grow: 1;
        overflow-y: auto;
        max-height: 60vh;
        scroll-behavior: smooth;
    }

    .chat-messages::-webkit-scrollbar {
        width: 10px;
    }

    .chat-messages::-webkit-scrollbar-thumb {
        background-color: var(--scrollbar-thumb);
        border-radius: 5px;
    }

    .chat-messages::-webkit-scrollbar-track {
        background-color: var(--scrollbar-track);
    }

    .message {
        margin-bottom: 20px;
        display: flex;
        flex-direction: column;
        max-width: 80%;
        animation: fadeIn 0.5s ease-out;
    }

    @keyframes fadeIn {
        from { opacity: 0; transform: translateY(20px); }
        to { opacity: 1; transform: translateY(0); }
    }

    .message.user {
        align-items: flex-end;
        align-self: flex-end;
    }

    .message.bot {
        align-items: flex-start;
    }

    .message p {
        padding: 15px 20px;
        border-radius: 20px;
        margin: 0;
        line-height: 1.5;
        position: relative;
        box-shadow: 0 5px 15px var(--shadow-color);
        color: #fff;
        font-size: 16px;
    }

    .message.user p {
        background: var(--message-user);
        border-bottom-right-radius: 0;
    }

    .message.bot p {
        background: var(--message-bot);
        border-bottom-left-radius: 0;
        color: var(--text-color);
    }

    .timestamp {
        font-size: 0.75em;
        color: #888;
        margin-top: 5px;
    }

    .chat-input-container {
        padding: 20px;
        background-color: var(--input-background);
        display: flex;
        align-items: center;
        gap: 10px;
    }

    .chat-input {
        flex-grow: 1;
        padding: 15px;
        border: 2px solid var(--input-border);
        border-radius: 30px;
        outline: none;
        font-size: 16px;
        resize: none;
        overflow-y: auto;
        max-height: 150px;
        background: var(--chat-background);
        color: var(--text-color);
        transition: all 0.3s ease;
    }

    .chat-input:focus {
        border-color: var(--secondary-color);
        box-shadow: 0 0 15px rgba(80, 200, 120, 0.1);
    }

    .chat-send-btn {
        padding: 15px 30px;
        background: var(--message-user);
        color: white;
        border: none;
        border-radius: 30px;
        cursor: pointer;
        font-size: 16px;
        font-weight: 600;
        transition: all 0.3s ease;
        box-shadow: 0 5px 15px var(--shadow-color);
    }

    .chat-send-btn:hover {
        transform: translateY(-2px);
        box-shadow: 0 7px 20px var(--shadow-color);
    }

    .modal {
        display: none;
        position: fixed;
        z-index: 1000;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        overflow: auto;
        background-color: rgba(0,0,0,0.4);
        animation: fadeIn 0.3s;
    }

    .modal-content {
        background: var(--chat-background);
        margin: 10% auto;
        padding: 40px;
        border: 1px solid var(--input-border);
        width: 80%;
        max-width: 500px;
        border-radius: 20px;
        box-shadow: 0 10px 50px rgba(0,0,0,0.1);
        color: var(--text-color);
    }

    .close {
        color: #aaa;
        float: right;
        font-size: 28px;
        font-weight: bold;
        cursor: pointer;
        transition: color 0.3s ease;
    }

    .close:hover,
    .close:focus {
        color: var(--primary-color);
    }

    #authorizationInput {
        width: 100%;
        padding: 15px;
        margin: 15px 0;
        border: 2px solid var(--input-border);
        border-radius: 10px;
        font-size: 16px;
        background-color: var(--input-background);
        color: var(--text-color);
        transition: all 0.3s ease;
    }

    #authorizationInput:focus {
        border-color: var(--secondary-color);
        box-shadow: 0 0 15px rgba(80, 200, 120, 0.1);
        outline: none;
    }

    #saveSettings {
        background: var(--message-user);
        color: white;
        border: none;
        padding: 15px 25px;
        border-radius: 10px;
        cursor: pointer;
        font-size: 16px;
        font-weight: 600;
        transition: all 0.3s ease;
        width: 100%;
        margin-top: 20px;
        box-shadow: 0 5px 15px var(--shadow-color);
    }

    #saveSettings:hover {
        transform: translateY(-2px);
        box-shadow: 0 7px 20px var(--shadow-color);
    }

    .theme-switch {
        display: flex;
        align-items: center;
        margin-top: 20px;
    }

    .switch {
        position: relative;
        display: inline-block;
        width: 60px;
        height: 34px;
        margin-right: 10px;
    }
    .switch input {
        opacity: 0;
        width: 0;
        height: 0;
    }

    .slider {
        position: absolute;
        cursor: pointer;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: #ccc;
        transition: .4s;
        border-radius: 34px;
    }

    .slider:before {
        position: absolute;
        content: "";
        height: 26px;
        width: 26px;
        left: 4px;
        bottom: 4px;
        background-color: white;
        transition: .4s;
        border-radius: 50%;
    }

    input:checked + .slider {
        background: var(--message-user);
    }

    input:checked + .slider:before {
        transform: translateX(26px);
    }

    .loading-overlay {
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.5);
        z-index: 1000;
        justify-content: center;
        align-items: center;
    }

    .loading-spinner {
        width: 50px;
        height: 50px;
        border: 3px solid #fff;
        border-top: 3px solid var(--primary-color);
        border-radius: 50%;
        animation: spin 1s linear infinite;
    }

    @keyframes spin {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
    }

    .tooltip {
        position: relative;
        display: inline-block;
    }

    .tooltip .tooltiptext {
        visibility: hidden;
        width: 120px;
        background-color: var(--primary-color);
        color: #fff;
        text-align: center;
        border-radius: 6px;
        padding: 5px 0;
        position: absolute;
        z-index: 1;
        bottom: 125%;
        left: 50%;
        margin-left: -60px;
        opacity: 0;
        transition: opacity 0.3s;
    }

    .tooltip:hover .tooltiptext {
        visibility: visible;
        opacity: 1;
    }

    .date-divider {
        text-align: center;
        margin: 20px 0;
        color: var(--text-color);
        font-size: 0.9em;
        opacity: 0.7;
    }

    .message-actions {
        display: flex;
        justify-content: flex-end;
        margin-top: 5px;
    }

    .message-action {
        background: none;
        border: none;
        color: var(--text-color);
        cursor: pointer;
        font-size: 0.8em;
        margin-left: 10px;
        opacity: 0.6;
        transition: opacity 0.3s ease;
    }

    .message-action:hover {
        opacity: 1;
    }

    @media (max-width: 768px) {
        .chat-container {
            height: 100vh;
            border-radius: 0;
        }

        .chat-header {
            font-size: 20px;
            padding: 15px;
        }

        .header-controls {
            flex-direction: column;
            align-items: flex-end;
        }

        #channelSelect, #modelSelect, #languageSelect {
            margin-bottom: 10px;
        }

        .chat-input, .chat-send-btn {
            font-size: 14px;
        }

        .modal-content {
            width: 90%;
            margin: 20% auto;
        }
    }
    </style>
</head>
<body>

<div class="chat-container">
    <div class="chat-header">
        <span data-i18n="title">星缘AI助手</span>
        <div class="header-controls">
            <select id="languageSelect" aria-label="选择语言">
                <option value="zh">中文</option>
                <option value="en">English</option>
            </select>
            <select id="channelSelect" aria-label="选择 API 渠道">
                <option value="v1" data-i18n="v1">V1极速(支持GPT全家桶)</option>
                <option value="v2" data-i18n="v2">V2包容(慢,可用三大家族)</option>
            </select>
            <select id="modelSelect" aria-label="选择模型"></select>
            <button class="btn tooltip" id="checkBalanceBtn" aria-label="查询请求余额">
                💰
                <span class="tooltiptext" data-i18n="checkBalance">查询请求余额</span>
            </button>
            <button class="btn tooltip" id="settingsBtn" aria-label="设置">
                ⚙️
                <span class="tooltiptext" data-i18n="settings">设置</span>
            </button>
        </div>
    </div>
    <div class="chat-messages" id="chat-messages">
        <!-- 消息将显示在这里 -->
    </div>
    <div class="chat-input-container">
        <textarea id="chat-input" class="chat-input" placeholder="输入你的消息..." rows="1" data-i18n-placeholder="inputPlaceholder"></textarea>
        <button id="chat-send-btn" class="chat-send-btn" data-i18n="send">发送</button>
    </div>
</div>

<div id="settingsModal" class="modal">
    <div class="modal-content">
        <span class="close">&times;</span>
        <h2 data-i18n="settings">设置</h2>
        <input type="text" id="authorizationInput" placeholder="输入 Authorization">
        <div class="theme-switch">
            <label class="switch">
                <input type="checkbox" id="themeSwitch">
                <span class="slider"></span>
            </label>
            <span data-i18n="darkMode">暗色模式</span>
        </div>
        <button id="saveSettings" data-i18n="saveSettings">保存设置</button>
    </div>
</div>

<div id="loadingOverlay" class="loading-overlay">
    <div class="loading-spinner"></div>
</div>

<script>
const chatMessages = document.getElementById('chat-messages');
const chatInput = document.getElementById('chat-input');
const chatSendBtn = document.getElementById('chat-send-btn');
const settingsBtn = document.getElementById('settingsBtn');
const settingsModal = document.getElementById('settingsModal');
const closeBtn = document.getElementsByClassName('close')[0];
const saveSettingsBtn = document.getElementById('saveSettings');
const authorizationInput = document.getElementById('authorizationInput');
const modelSelect = document.getElementById('modelSelect');
const themeSwitch = document.getElementById('themeSwitch');
const channelSelect = document.getElementById('channelSelect');
const loadingOverlay = document.getElementById('loadingOverlay');
const checkBalanceBtn = document.getElementById('checkBalanceBtn');
const languageSelect = document.getElementById('languageSelect');
const chatHistory = [];

let userScrolled = false;
let authorization = localStorage.getItem('authorization') || '';
let selectedModel = localStorage.getItem('selectedModel') || 'gpt-3.5-turbo-0125';
let selectedChannel = localStorage.getItem('selectedChannel') || 'v1';

// 获取URL查询字符串
const queryString = window.location.search;
// 使用URLSearchParams解析查询字符串
const urlParams = new URLSearchParams(queryString);
// 提取token参数
let urlParamsToken = urlParams.get('token');

// 如果URL中有token,则保存到localStorage
if (urlParamsToken) {
    localStorage.setItem('authorization', urlParamsToken);
    authorization = urlParamsToken;
    // 清除URL中的token参数
    window.history.replaceState({}, document.title, window.location.pathname);
}

function showLoading() {
    loadingOverlay.style.display = 'flex';
}

function hideLoading() {
    loadingOverlay.style.display = 'none';
}

function appendMessage(content, sender) {
    const message = document.createElement('div');
    message.classList.add('message', sender);
    const timestamp = new Date().toLocaleTimeString();
    message.innerHTML = `
        <p>${content}</p>
        <span class="timestamp">${timestamp}</span>
        <div class="message-actions">
            <button class="message-action copy-btn">复制</button>
            ${sender === 'bot' ? '<button class="message-action regenerate-btn">重新生成</button>' : ''}
        </div>
    `;
    
    const lastMessage = chatMessages.lastElementChild;
    if (lastMessage && !lastMessage.classList.contains('date-divider')) {
        const lastDate = new Date(lastMessage.querySelector('.timestamp').textContent);
        const currentDate = new Date();
        if (lastDate.toDateString() !== currentDate.toDateString()) {
            const dateDivider = document.createElement('div');
            dateDivider.classList.add('date-divider');
            dateDivider.textContent = currentDate.toLocaleDateString();
            chatMessages.appendChild(dateDivider);
        }
    }

    chatMessages.appendChild(message);

    if (!userScrolled) {
        chatMessages.scrollTop = chatMessages.scrollHeight;
    }

    // 添加复制和重新生成功能
    message.querySelector('.copy-btn').addEventListener('click', () => copyMessage(content));
    if (sender === 'bot') {
        message.querySelector('.regenerate-btn').addEventListener('click', () => regenerateResponse());
    }

    return message;
}

function copyMessage(content) {
    navigator.clipboard.writeText(content).then(() => {
        alert('消息已复制到剪贴板');
    }).catch(err => {
        console.error('复制失败:', err);
    });
}

function regenerateResponse() {
    // 移除最后一条bot消息
    chatHistory.pop();
    chatMessages.removeChild(chatMessages.lastElementChild);
    // 重新生成响应
    getBotResponse(chatHistory[chatHistory.length - 1].content);
}

async function getBotResponse(userMessage) {
    try {
        showLoading();
        const botMessageElement = appendMessage("", 'bot');
        const loadingSpinner = document.createElement('div');
        loadingSpinner.classList.add('loading');
        botMessageElement.prepend(loadingSpinner);

        chatHistory.push({
            "role": "user",
            "content": userMessage
        });

        const apiUrl = selectedChannel === 'v1' ? 'https://i-i.win/v1/v1/chat/completions' : 'https://i-i.win/v2/v1/chat/completions';
        const response = await fetch(apiUrl, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': authorization,
            },
            body: JSON.stringify({
                "messages": chatHistory,
                "stream": "true",
                "model": selectedModel
            })
        });

        const reader = response.body.getReader();
        const decoder = new TextDecoder('utf-8');
        let partialContent = "";

        while (true) {
            const {done, value} = await reader.read();
            if (done) break;

            const chunk = decoder.decode(value, {stream: true});
            partialContent += chunk;

            const lines = partialContent.split('\n');

            for (let line of lines) {
                if (line.trim().startsWith("data:")) {
                    const jsonStr = line.replace("data:", "").trim();

                    if (jsonStr === "[DONE]" || jsonStr === "") continue;

                    try {
                        const jsonData = JSON.parse(jsonStr);
                        const content = jsonData.choices[0].delta.content;

                        if (content) {
                            loadingSpinner.remove();
                            botMessageElement.querySelector('p').textContent += content;
                            if (!userScrolled) {
                                chatMessages.scrollTop = chatMessages.scrollHeight;
                            }
                        }
                    } catch (error) {
                        console.error("解析JSON时出错: ", error);
                    }
                }
            }

            partialContent = lines[lines.length - 1];
        }

        const botResponse = botMessageElement.querySelector('p').textContent;
        chatHistory.push({
            "role": "assistant",
            "content": botResponse
        });

        return botResponse;
    } catch (error) {
        console.error('获取机器人响应时出错:', error);
        return "抱歉,连接服务器时出现错误。";
    } finally {
        hideLoading();
    }
}

function adjustTextareaHeight() {
    chatInput.style.height = 'auto';
    chatInput.style.height = (chatInput.scrollHeight) + 'px';
}

function updateTheme() {
    const isDarkMode = localStorage.getItem('darkMode') === 'true';
    document.body.classList.toggle('dark-mode', isDarkMode);
    themeSwitch.checked = isDarkMode;
}

function updateModelOptions() {
    const v1Models = [
        "gpt-3.5-turbo-0125", "gpt-4o-mini-2024-07-18", "gpt-4-0314", "gpt-4-32k-0314", 
        "gpt-4-0613", "gpt-4-1106-preview", "gpt-4-1106-vision-preview", "gpt-4-0125-preview", 
        "gpt-4-turbo-2024-04-09", "gpt-4o-2024-05-13", "gpt-4o-2024-08-06", "chatgpt-4o-latest"
    ];
    const v2Models = [
        "gpt-3.5-turbo", "gpt-4o-mini-2024-07-18", "gpt-4o", "gpt-4o-2024-08-06", "chatgpt-4o-latest", 
        "claude-2", "claude-2.0", "claude-2.1", "claude-3-sonnet-20240229", "claude-3-haiku-20240307", 
        "claude-3-opus-20240229", "claude-3-5-sonnet-20240620", 
        "gemini-pro", "gemini-1.0-pro", "gemini-1.0-pro-latest", "gemini-1.5-pro", "gemini-1.5-flash",
        "mixtral-8x7b-32768"
    ];
    
    const models = selectedChannel === 'v1' ? v1Models : v2Models;
    modelSelect.innerHTML = models.map(model => `<option value="${model}">${model}</option>`).join('');
    modelSelect.value = selectedModel;
}

async function checkBalance() {
    try {
        showLoading();
        const response = await fetch('https://i-i.win/getTimes', {
            method: 'POST',
            headers: {
                'Authorization': authorization
            }
        });
        const data = await response.json();
        hideLoading();
        alert(`剩余额度:${data.remainingTimes}\n\n注意:此额度为两种渠道共用。如果额度用完,请联系原作者添加。`);
    } catch (error) {
        console.error('查询余额时出错:', error);
        hideLoading();
        alert('查询余额失败,请稍后重试');
    }
}

chatMessages.addEventListener('scroll', () => {
    const isAtBottom = chatMessages.scrollTop + chatMessages.clientHeight >= chatMessages.scrollHeight - 10;
    userScrolled = !isAtBottom;
});

chatSendBtn.addEventListener('click', async () => {
    const userMessage = chatInput.value.trim();
    if (userMessage !== "") {
        appendMessage(userMessage, 'user');
        chatInput.value = '';
        adjustTextareaHeight();
        await getBotResponse(userMessage);
    }
});

chatInput.addEventListener('keydown', (e) => {
    if (e.key === 'Enter' && !e.shiftKey) {
        e.preventDefault();
        chatSendBtn.click();
    }
});

chatInput.addEventListener('input', adjustTextareaHeight);

settingsBtn.onclick = () => {
    settingsModal.style.display = "block";
    authorizationInput.value = authorization;
}

closeBtn.onclick = () => {
    settingsModal.style.display = "none";
}

window.onclick = (event) => {
    if (event.target == settingsModal) {
        settingsModal.style.display = "none";
    }
}

saveSettingsBtn.onclick = () => {
    authorization = authorizationInput.value;
    localStorage.setItem('authorization', authorization);
    settingsModal.style.display = "none";
}

themeSwitch.addEventListener('change', () => {
    localStorage.setItem('darkMode', themeSwitch.checked);
    updateTheme();
});

channelSelect.addEventListener('change', (e) => {
    selectedChannel = e.target.value;
    localStorage.setItem('selectedChannel', selectedChannel);
    updateModelOptions();
});

modelSelect.addEventListener('change', (e) => {
    selectedModel = e.target.value;
    localStorage.setItem('selectedModel', selectedModel);
});

checkBalanceBtn.addEventListener('click', checkBalance);

// 多语言支持
const translations = {
    'zh': {
        'title': '星缘AI助手',
        'v1': 'V1极速(支持GPT全家桶)',
        'v2': 'V2包容(慢,可用三大家族)',
        'settings': '设置',
        'send': '发送',
        'inputPlaceholder': '输入你的消息...',
        'saveSettings': '保存设置',
        'checkBalance': '查询余额',
        'darkMode': '暗色模式'
    },
    'en': {
        'title': 'AI Chat Assistant',
        'v1': 'V1 Channel (Fast, Fewer Models)',
        'v2': 'V2 Channel (Slower, More Models)',
        'settings': 'Settings',
        'send': 'Send',
        'inputPlaceholder': 'Enter your message...',
        'saveSettings': 'Save Settings',
        'checkBalance': 'Check Balance',
        'darkMode': 'Dark Mode'
    }
};

function setLanguage(lang) {
    document.querySelectorAll('[data-i18n]').forEach(element => {
        const key = element.getAttribute('data-i18n');
        if (translations[lang] && translations[lang][key]) {
            element.textContent = translations[lang][key];
        }
    });
    document.querySelectorAll('[data-i18n-placeholder]').forEach(element => {
        const key = element.getAttribute('data-i18n-placeholder');
        if (translations[lang] && translations[lang][key]) {
            element.placeholder = translations[lang][key];
        }
    });
    document.documentElement.lang = lang;
}

languageSelect.addEventListener('change', (e) => {
    setLanguage(e.target.value);
    localStorage.setItem('language', e.target.value);
});

document.addEventListener('DOMContentLoaded', () => {
    channelSelect.value = selectedChannel;
    updateModelOptions();
    updateTheme();
    const savedLanguage = localStorage.getItem('language') || 'zh';
    languageSelect.value = savedLanguage;
    setLanguage(savedLanguage);

    // 添加欢迎消息
    appendMessage("欢迎使用星缘AI助手!我是您的智能对话伙伴,随时准备回答您的问题和提供帮助。请问有什么我可以为您做的吗?", 'bot');
});

// 添加自动保存聊天记录功能
function saveChat() {
    localStorage.setItem('chatHistory', JSON.stringify(chatHistory));
}

function loadChat() {
    const savedChat = localStorage.getItem('chatHistory');
    if (savedChat) {
        const parsedChat = JSON.parse(savedChat);
        parsedChat.forEach(msg => {
            appendMessage(msg.content, msg.role === 'user' ? 'user' : 'bot');
        });
        chatHistory.push(...parsedChat);
    }
}

// 在页面加载时加载聊天记录
loadChat();

// 在每次发送消息后保存聊天记录
chatSendBtn.addEventListener('click', saveChat);

// 添加清除聊天记录功能
function clearChat() {
    chatHistory.length = 0;
    chatMessages.innerHTML = '';
    localStorage.removeItem('chatHistory');
    appendMessage("聊天记录已清除。有什么新的问题我可以帮您解答吗?", 'bot');
}

// 添加清除聊天记录按钮
const clearChatBtn = document.createElement('button');
clearChatBtn.textContent = '清除聊天';
clearChatBtn.classList.add('btn', 'tooltip');
clearChatBtn.innerHTML = '🗑️ <span class="tooltiptext">清除聊天记录</span>';
clearChatBtn.addEventListener('click', clearChat);
document.querySelector('.header-controls').appendChild(clearChatBtn);

</script>
</body>
</html>
50 个赞

以后都不取名了,没啥必要:rofl:
4天后我决定还是给他起个名字 就叫做AI幻境吧

3 个赞

厉害呢 等服务器好了 我就征用了 :bili_040:

4 个赞

没问题的,现在准备研究一下具体的请求参数
比如这里为什么两个v1

克劳德3.5用不了这就对劲了

3 个赞

:rofl: 欢迎萌新,祝你玩得开心

不错,感谢分享

2 个赞

因为后面的v1是为了包容一些平台
至于前面的v1 和 v2

/v1只有gpt模型 但是快啊
/v2模型比较全 稍微慢个几百毫秒

像你的克劳德3.5 就得用v2的了

1 个赞

听懂了,现在终于明白之前那个帖子评论“v2/v1”是什么意思了:rofl:
感谢解惑

感谢分享拿来玩玩

:smiling_face_with_three_hearts:
如果不能用,请多多关注原帖信息哦

感谢分享这个代码

2 个赞

不错,感谢分享

更新了,更新了,服务器维护的怎么样了呢?
我目前简单更新了代码,已经达到22000字节~
现在支持两种渠道了
简单改动一下页面
现在支持中文和英文:smiling_face_with_three_hearts:

1 个赞

敲代码这么迅速?

1 个赞

服务器好了.

1 个赞

更新了,现在有在线网站可以直接用
Websim收费了,哭死
现在好像只能用克劳德haiku模型了

1 个赞

用我的演示站试了一下,还是一如既往的太快啦
再次膜拜
克劳德还是用不了,我再去检查一下代码


唔…

2 个赞


成功 准备调参

1 个赞

好离谱的回答

2 个赞

克劳德暂时维护