<html><head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Enhanced ChatGPT UI Clone with Syntax Highlighting</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-dark.min.css"><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/javascript.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/python.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/css.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/html.min.js"></script><style>
    body {
        font-family: 'Söhne', 'ui-sans-serif', 'system-ui', '-apple-system', 'Segoe UI', 'Roboto', 'Ubuntu', 'Cantarell', 'Noto Sans', 'sans-serif';
        background-color: #343541;
        color: #ececf1;
    }
    @keyframes fadeIn {
        from { opacity: 0; transform: translateY(10px); }
        to { opacity: 1; transform: translateY(0); }
    }
    .message-bubble {
        animation: fadeIn 0.3s ease-out;
        max-width: 100%;
        padding: 1.5rem;
        line-height: 1.75;
        display: flex;
        align-items: flex-start;
    }
    .gpt-message { background-color: #444654; }
    .user-message { background-color: #343541; }
    .model-toggle {
        background-color: #40414f;
        color: #ececf1;
        border: 1px solid #565869;
        border-radius: 0.375rem;
        padding: 0.5rem 0.75rem;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: space-between;
        width: 180px;
        transition: background-color 0.2s;
    }
    .model-toggle:hover { background-color: #565869; }
    .model-list {
        position: absolute;
        top: 100%;
        left: 0;
        width: 180px;
        background-color: #40414f;
        border: 1px solid #565869;
        border-radius: 0.375rem;
        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        z-index: 10;
    }
    .model-list div {
        cursor: pointer;
        padding: 0.5rem 0.75rem;
        transition: background-color 0.2s;
    }
    .model-list div:hover { background-color: #565869; }
    #user-input {
        resize: none;
        overflow-y: hidden;
        background-color: #40414f;
        color: #ececf1;
        border-color: #565869;
    }
    #user-input::placeholder { color: #8e8ea0; }
    .send-button {
        position: absolute;
        bottom: 0.75rem;
        right: 0.75rem;
        padding: 0.25rem;
        background-color: transparent;
        border: none;
        cursor: pointer;
        opacity: 0.7;
        transition: opacity 0.2s;
    }
    .send-button:hover { opacity: 1; }
    ::-webkit-scrollbar { width: 10px; }
    ::-webkit-scrollbar-track { background: #2a2b32; }
    ::-webkit-scrollbar-thumb {
        background: #565869;
        border-radius: 5px;
    }
    ::-webkit-scrollbar-thumb:hover { background: #676980; }
    .avatar {
        width: 30px;
        height: 30px;
        border-radius: 2px;
        margin-right: 1rem;
    }
    .chat-title {
        font-size: 0.875rem;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 100%;
    }
    .typing-indicator {
        display: inline-block;
        width: 20px;
        height: 10px;
    }
    .typing-indicator::after {
        content: '...';
        animation: typing 1s infinite;
    }
    @keyframes typing {
        0% { content: '.'; }
        33% { content: '..'; }
        66% { content: '...'; }
    }
    .sidebar-button {
        width: 100%;
        text-align: left;
        padding: 0.75rem;
        border-radius: 0.375rem;
        transition: background-color 0.2s;
    }
    .sidebar-button:hover { background-color: rgba(255, 255, 255, 0.1); }
    .logo {
        width: 32px;
        height: 32px;
        margin-right: 0.5rem;
    }
    .image-upload-button {
        cursor: pointer;
        padding: 0.25rem;
        background-color: transparent;
        border: none;
        opacity: 0.7;
        transition: opacity 0.2s;
    }
    .image-upload-button:hover { opacity: 1; }
    .uploaded-image {
        max-width: 300px;
        max-height: 300px;
        margin-top: 10px;
    }
    pre code.hljs {
        padding: 1em;
        border-radius: 0.5rem;
        margin: 0.5em 0;
    }
</style></head>
<body>

<div class="flex h-screen">
    <!-- Sidebar -->
    <aside class="w-64 bg-[#202123] text-white p-4 flex flex-col">
        <div class="flex-shrink-0 mb-4">
            <button id="new-chat" class="sidebar-button flex items-center">
                <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4 mr-3" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
                New chat
            </button>
        </div>
        <nav id="chat-list" class="flex-1 overflow-y-auto mb-4">
            <!-- Chat history will be dynamically added here -->
        </nav>
        <div class="border-t border-white/20 pt-2">
            <button id="buy-plus" class="sidebar-button flex items-center">
                <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4 mr-3">
                    <path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
                </svg>
                Upgrade to Plus
            </button>
            <button id="toggle-theme" class="sidebar-button flex items-center mt-2">
                <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4 mr-3" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>
                Dark mode
            </button>
            <button id="clear-conversations" class="sidebar-button flex items-center mt-2">
                <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4 mr-3" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>
                Clear conversations
            </button>
        </div>
        <div class="mt-4 flex items-center">
            <img src="https://i.pinimg.com/736x/7a/da/0f/7ada0f01f2d02496cf16d0161f9c9b23.jpg" alt="ChatGPT Logo" class="logo">
            <span class="font-semibold">ChatGPT</span>
        </div>
    </aside>

    <!-- Main Chat Area -->
    <main class="flex-1 flex flex-col bg-[#343541] overflow-hidden">
        <div id="chat-messages" class="flex-1 overflow-y-auto p-4"><div class="message-bubble gpt-message"><img class="avatar" src="https://i.pinimg.com/originals/01/da/4a/01da4aa52ffbd12a2e50d80b8278851f.jpg" alt="ChatGPT Avatar"><div class="flex-1">Hello! I'm ChatGPT. How can I assist you today?</div></div><div class="message-bubble gpt-message"><img class="avatar" src="https://i.pinimg.com/originals/01/da/4a/01da4aa52ffbd12a2e50d80b8278851f.jpg" alt="ChatGPT Avatar"><div class="flex-1">Oi! Aqui está um exemplo de código em JavaScript:<br><br><strong>Função de exemplo:</strong><br><pre><code class="javascript">function greet(name) {\n  console.log(Olá, ${name}! Bem-vindo ao mundo da programação.);\n}\n\ngreet('Usuário');\n</code></pre><br>Este código define uma função <strong>greet</strong> que recebe um nome como parâmetro e imprime uma saudação personalizada no console.</div></div></div>

        <!-- Input and Model Selection -->
        <div class="w-full p-4 border-t border-white/20 bg-[#343541]">
            <div class="max-w-3xl mx-auto">
                <div class="flex items-center justify-between mb-3">
                    <div class="relative">
                        <button id="toggle-model" class="model-toggle">
                            <span id="model-label">1o-mini</span>
                            <svg class="h-4 w-4 text-gray-400 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
                        </button>
                        <div id="model-list" class="model-list hidden">
                            <div data-model="1o-mini">1o-mini</div>
                        </div>
                    </div>
                </div>
                <form id="chat-form" class="relative">
                    <textarea id="user-input" class="w-full border rounded-lg p-3 pr-20 focus:outline-none focus:ring-2 focus:ring-[#10a37f]" placeholder="Send a message" rows="1"></textarea>
                    <label for="image-upload" class="image-upload-button absolute right-12 bottom-3">
                        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
                            <path stroke-linecap="round" stroke-linejoin="round" d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"></path>
                        </svg>
                    </label>
                    <input type="file" id="image-upload" accept="image/*" class="hidden">
                    <button type="submit" class="send-button text-white absolute right-3 bottom-4">
                        <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><line x1="22" y1="2" x2="11" y2="13"></line><polygon points="22 2 15 22 11 13 2 9 22 2"></polygon></svg>
                    </button>
                </form>
                <div id="uploaded-image-container"></div>
                <p class="text-xs text-center mt-2 text-gray-400">ChatGPT can make mistakes. Consider checking important information.</p>
            </div>
        </div>
    </main>
</div>

<div id="plus-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
    <div class="bg-white text-black p-6 rounded-lg max-w-md">
        <h2 class="text-2xl font-bold mb-4">Upgrade to ChatGPT Plus</h2>
        <p class="mb-4">Get access to 1o-preview and other exclusive features! 🚀✨</p>
        <button id="confirm-plus" class="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600">Upgrade Now</button>
        <button id="close-modal" class="ml-2 text-gray-600 hover:text-gray-800">Cancel</button>
    </div>
</div>

<script>
    document.addEventListener('DOMContentLoaded', () => {
        const chatMessages = document.getElementById('chat-messages');
        const chatForm = document.getElementById('chat-form');
        const userInput = document.getElementById('user-input');
        const toggleModel = document.getElementById('toggle-model');
        const modelLabel = document.getElementById('model-label');
        const modelList = document.getElementById('model-list');
        const newChatButton = document.getElementById('new-chat');
        const chatList = document.getElementById('chat-list');
        const clearConversationsButton = document.getElementById('clear-conversations');
        const toggleThemeButton = document.getElementById('toggle-theme');
        const buyPlusButton = document.getElementById('buy-plus');
        const plusModal = document.getElementById('plus-modal');
        const confirmPlusButton = document.getElementById('confirm-plus');
        const closeModalButton = document.getElementById('close-modal');
        const imageUpload = document.getElementById('image-upload');
        const uploadedImageContainer = document.getElementById('uploaded-image-container');

        let currentModel = '1o-mini';
        let isPlus = false;
        let conversations = JSON.parse(localStorage.getItem('conversations')) || [];
        let currentConversationId = null;
        let uploadedImage = null;

        function addMessage(content, isUser = false) {
            const messageDiv = document.createElement('div');
            messageDiv.className = message-bubble ${isUser ? 'user-message' : 'gpt-message'};
            
            const avatar = document.createElement('img');
            avatar.className = 'avatar';
            avatar.src = isUser ? 'https://ui-avatars.com/api/?name=User&background=random' : 'https://i.pinimg.com/736x/7a/da/0f/7ada0f01f2d02496cf16d0161f9c9b23.jpg';
            avatar.alt = isUser ? 'User Avatar' : 'ChatGPT Avatar';
            
            const innerDiv = document.createElement('div');
            innerDiv.className = 'flex-1';
            innerDiv.textContent = content;
            
            messageDiv.appendChild(avatar);
            messageDiv.appendChild(innerDiv);
            chatMessages.appendChild(messageDiv);
            chatMessages.scrollTop = chatMessages.scrollHeight;

            if (currentConversationId !== null) {
                const conversation = conversations.find(c => c.id === currentConversationId);
                if (conversation) {
                    conversation.messages.push({ content, isUser });
                    saveConversations();
                }
            }
        }

        function showTypingIndicator() {
            const typingDiv = document.createElement('div');
            typingDiv.className = 'message-bubble gpt-message';
            typingDiv.innerHTML = '<img src="https://i.pinimg.com/736x/7a/da/0f/7ada0f01f2d02496cf16d0161f9c9b23.jpg" alt="ChatGPT Avatar" class="avatar"><div class="typing-indicator"></div>';
            chatMessages.appendChild(typingDiv);
            chatMessages.scrollTop = chatMessages.scrollHeight;
            return typingDiv;
        }

        async function getBotResponse(userMessage, imageData = null) {
            const response = await fetch('/test/generate', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    userMessage,
                    model: currentModel,
                    imageData
                }),
            });
            const data = await response.json();
            return data.botResponse;
        }

        function createNewChat() {
            const id = Date.now();
            const title = New Chat ${conversations.length + 1};
            conversations.push({ id, title, messages: [] });
            currentConversationId = id;
            saveConversations();
            updateChatList();
            clearChatMessages();
            addMessage("Hello! I'm ChatGPT. How can I assist you today?");
        }

        function updateChatList() {
            chatList.innerHTML = '';
            conversations.forEach(conv => {
                const chatItem = document.createElement('div');
                chatItem.className = 'p-3 sidebar-button hover:bg-gray-500/10 rounded-lg cursor-pointer mb-1 chat-title';
                chatItem.textContent = conv.title;
                chatItem.dataset.id = conv.id;
                chatItem.addEventListener('click', () => loadConversation(conv.id));
                chatList.appendChild(chatItem);
            });
        }

        function loadConversation(id) {
            currentConversationId = id;
            clearChatMessages();
            const conversation = conversations.find(c => c.id === id);
            if (conversation) {
                conversation.messages.forEach(msg => addMessage(msg.content, msg.isUser));
            }
        }

        function clearChatMessages() {
            chatMessages.innerHTML = '';
        }

        function saveConversations() {
            localStorage.setItem('conversations', JSON.stringify(conversations));
        }

        chatForm.addEventListener('submit', async (e) => {
            e.preventDefault();
            const userMessage = userInput.value.trim();
            if (userMessage || uploadedImage) {
                addMessage(userMessage, true);
                if (uploadedImage) {
                    const img = document.createElement('img');
                    img.src = uploadedImage;
                    img.className = 'uploaded-image';
                    chatMessages.lastElementChild.appendChild(img);
                }
                userInput.value = '';
                adjustTextareaHeight();

                const typingIndicator = showTypingIndicator();
                const botResponse = await getBotResponse(userMessage, uploadedImage);
                typingIndicator.remove();
                addMessage(botResponse);

                uploadedImage = null;
                uploadedImageContainer.innerHTML = '';
            }
        });

        toggleModel.addEventListener('click', () => {
            modelList.classList.toggle('hidden');
        });

        modelList.addEventListener('click', (e) => {
            if (e.target.dataset.model) {
                if (e.target.dataset.model === '1o-preview' && !isPlus) {
                    alert('1o-preview is only available for Plus members. Please upgrade to access this model.');
                } else {
                    currentModel = e.target.dataset.model;
                    modelLabel.textContent = e.target.textContent;
                    modelList.classList.add('hidden');
                }
            }
        });

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

        userInput.addEventListener('input', adjustTextareaHeight);

        document.addEventListener('click', (e) => {
            if (!toggleModel.contains(e.target)) {
                modelList.classList.add('hidden');
            }
        });

        newChatButton.addEventListener('click', createNewChat);

        clearConversationsButton.addEventListener('click', () => {
            conversations = [];
            currentConversationId = null;
            saveConversations();
            updateChatList();
            clearChatMessages();
            addMessage("Conversations cleared. How can I help you today?");
        });

        buyPlusButton.addEventListener('click', () => {
            plusModal.classList.remove('hidden');
        });

        closeModalButton.addEventListener('click', () => {
            plusModal.classList.add('hidden');
        });

        confirmPlusButton.addEventListener('click', () => {
            isPlus = true;
            plusModal.classList.add('hidden');
            buyPlusButton.textContent = 'Plus Member 🌟';
            buyPlusButton.disabled = true;

            const previewOption = document.createElement('div');
            previewOption.dataset.model = '1o-preview';
            previewOption.textContent = '1o-preview';
            modelList.appendChild(previewOption);
        });

        imageUpload.addEventListener('change', (e) => {
            const file = e.target.files[0];
            if (file) {
                const reader = new FileReader();
                reader.onload = (e) => {
                    uploadedImage = e.target.result;
                    const img = document.createElement('img');
                    img.src = uploadedImage;
                    img.className = 'uploaded-image';
                    uploadedImageContainer.innerHTML = '';
                    uploadedImageContainer.appendChild(img);
                };
                reader.readAsDataURL(file);
            }
        });

        updateChatList();
        if (conversations.length === 0) {
            createNewChat();
        } else {
            loadConversation(conversations[conversations.length - 1].id);
        }
    });
</script>
</body>
</html>

pode me ajudar ele so enmvia e funciona no index.html ja no test.html

const express = require('express');
const cors = require('cors');
require('dotenv').config();
const { GoogleGenerativeAI } = require('@google/generative-ai');

const app = express();
const PORT = process.env.PORT || 3000;

// Middleware
app.use(cors());
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));

// Initialize the models
const genAI = new GoogleGenerativeAI(process.env.API_KEY);
const modelMini = genAI.getGenerativeModel({ model: 'gemini-1.0-pro' });
const modelPreview = genAI.getGenerativeModel({ model: 'gemini-1.5-flash' });

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/public/index.html');
});

app.get('/test', (req, res) => {
    res.sendFile(__dirname + '/public/test.html');
  });

// Função para criar prompts específicos para cada modelo
function createPrompt(userMessage, model) {
    if (model === '1o-preview') {
      return "Olá! Sou seu assistente aqui para ajudar. Estou sempre pronto para fornecer informações úteis e precisas. Ao responder suas perguntas, vou garantir que as minhas respostas sejam claras e amigáveis. \n\nAqui estão algumas diretrizes que sigo:\n1. Respondo diretamente à sua pergunta.\n2. Incluo informações adicionais relevantes, quando necessário.\n3. Nunca menciono marcas ou entidades externas.\n\nAgora, me diga: \"" + userMessage + "\"";
    } else {
      return "Oi! Estou aqui para ajudar com qualquer dúvida que você tenha. Minha missão é ser claro e direto nas respostas. \n\nVou seguir estas diretrizes:\n1. Responder de forma concisa e eficaz.\n2. Evitar mencionar marcas ou entidades externas.\n3. Utilizar uma linguagem amigável e acessível.\n\nEntão, por favor, me conte: \"" + userMessage + "\"";
    }
}

app.post('/generate', async (req, res) => {
  const { userMessage, model, imageData } = req.body;

  if (!userMessage && !imageData) {
    return res.status(400).json({ error: 'No input provided.' });
  }

  try {
    let response;
    const selectedModel = model === '1o-preview' ? modelPreview : modelMini;
    const maxTokens = model === '1o-preview' ? 4000 : 1000;

    let parts = [];

    // Cria o prompt apropriado para o modelo selecionado
    const prompt = createPrompt(userMessage, model);
    parts.push({ text: prompt });

    if (imageData) {
      parts.push({
        inlineData: {
          data: imageData.split(',')[1],
          mimeType: 'image/jpeg'
        }
      });
    }

    const result = await selectedModel.generateContent({
      contents: [{ role: 'user', parts }],
      generationConfig: { maxOutputTokens: maxTokens },
    });

    response = result.response;
    const textResponse = response.text();
    res.json({ botResponse: textResponse });
  } catch (error) {
    console.error('Error generating response:', error);
    res.status(500).json({ error: 'Error generating AI response.' });
  }
});

app.listen(PORT, () => {
  console.log(Server running on port ${PORT});
})

n funciona