From 1633bd7927cfd0f3c885251b1004464cc1a7de8a Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 22 Jan 2026 03:52:16 +0000 Subject: [PATCH] random AI 3.0 --- api/history.php | 53 +++++++++++++++ assets/css/custom.css | 56 ++++++++++++++++ assets/js/main.js | 150 +++++++++++++++++++++++++++++++++++++----- index.php | 96 ++++++++++++--------------- 4 files changed, 284 insertions(+), 71 deletions(-) create mode 100644 api/history.php diff --git a/api/history.php b/api/history.php new file mode 100644 index 0000000..409e972 --- /dev/null +++ b/api/history.php @@ -0,0 +1,53 @@ +query("SELECT id, title, mode, created_at FROM chats ORDER BY created_at DESC LIMIT 20"); + $chats = $stmt->fetchAll(); + echo json_encode(['success' => true, 'chats' => $chats]); + } + elseif ($action === 'messages') { + $chatId = $_GET['chat_id'] ?? null; + if (!$chatId) { + echo json_encode(['error' => 'Chat ID is required']); + exit; + } + + // Fetch all messages for this chat + $stmt = db()->prepare("SELECT role, content, created_at FROM messages WHERE chat_id = ? ORDER BY id ASC"); + $stmt->execute([$chatId]); + $messages = $stmt->fetchAll(); + + // Also fetch chat details (to restore mode) + $stmt = db()->prepare("SELECT mode FROM chats WHERE id = ?"); + $stmt->execute([$chatId]); + $chat = $stmt->fetch(); + + echo json_encode([ + 'success' => true, + 'messages' => $messages, + 'mode' => $chat['mode'] ?? 'regular' + ]); + } + elseif ($action === 'delete') { + $chatId = $_GET['chat_id'] ?? null; + if (!$chatId) { + echo json_encode(['error' => 'Chat ID is required']); + exit; + } + + $stmt = db()->prepare("DELETE FROM chats WHERE id = ?"); + $stmt->execute([$chatId]); + echo json_encode(['success' => true]); + } + else { + echo json_encode(['error' => 'Invalid action']); + } +} catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); +} \ No newline at end of file diff --git a/assets/css/custom.css b/assets/css/custom.css index 5110b82..608d810 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -204,3 +204,59 @@ body, #sidebar, #main-content, .message, #chat-input { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0,0,0,0.15); } + +/* History Item Styling */ +.history-item { + font-size: 0.9rem; + transition: all 0.2s ease; +} + +.history-item .delete-chat { + visibility: hidden; + cursor: pointer; +} + +.history-item:hover .delete-chat { + visibility: visible; +} + +.history-item:hover { + background-color: var(--hover-bg); +} + +.history-item.active { + background-color: var(--active-bg); + border-left: 3px solid var(--accent-color); +} + +/* Enhanced Theme Swatches */ +.theme-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); + gap: 12px; +} + +.theme-swatch { + height: 60px; + border-radius: 10px; + cursor: pointer; + border: 2px solid var(--border-color); + transition: all 0.2s ease; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.75rem; + font-weight: 600; + text-align: center; + padding: 5px; +} + +.theme-swatch:hover { + transform: scale(1.05); + border-color: var(--accent-color); +} + +.theme-swatch.active { + border-color: var(--accent-color); + box-shadow: 0 0 0 2px var(--accent-color); +} diff --git a/assets/js/main.js b/assets/js/main.js index 1c4234f..218b7af 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -5,6 +5,7 @@ document.addEventListener('DOMContentLoaded', () => { const modeItems = document.querySelectorAll('.mode-item'); const currentModeBadge = document.getElementById('current-mode-badge'); const newChatBtn = document.getElementById('new-chat-btn'); + const chatHistoryList = document.getElementById('chat-history'); // Settings elements const creativityRange = document.getElementById('creativity-range'); @@ -39,15 +40,132 @@ document.addEventListener('DOMContentLoaded', () => {

How can I help you in this mode?

`; + + // Remove active class from history items + document.querySelectorAll('.history-item').forEach(i => i.classList.remove('active')); } newChatBtn.addEventListener('click', startNewChat); + // --- History Loading --- + async function loadHistory() { + try { + const resp = await fetch('api/history.php?action=list'); + const data = await resp.json(); + if (data.success) { + renderHistory(data.chats); + } + } catch (e) { + console.error('Failed to load history:', e); + } + } + + function renderHistory(chats) { + if (!chats || chats.length === 0) { + chatHistoryList.innerHTML = '
No recent chats
'; + return; + } + + chatHistoryList.innerHTML = chats.map(chat => ` +
+ + ${escapeHtml(chat.title)} + +
+ `).join(''); + + // Add event listeners to history items + chatHistoryList.querySelectorAll('.history-item').forEach(item => { + item.addEventListener('click', (e) => { + if (e.target.classList.contains('delete-chat')) { + deleteChat(e.target.dataset.id); + return; + } + loadChat(item.dataset.id); + }); + }); + } + + function getModeIcon(mode) { + switch(mode) { + case 'coding': return 'code-slash'; + case 'game': return 'controller'; + case 'app': return 'window'; + default: return 'chat-left-dots'; + } + } + + async function loadChat(chatId) { + if (currentChatId == chatId) return; + + chatWindow.innerHTML = '
'; + + try { + const resp = await fetch(`api/history.php?action=messages&chat_id=${chatId}`); + const data = await resp.json(); + if (data.success) { + currentChatId = chatId; + currentMode = data.mode; + + // Update Sidebar Mode UI + modeItems.forEach(i => { + if (i.dataset.mode === currentMode) i.classList.add('active'); + else i.classList.remove('active'); + }); + + // Update badge + const activeModeItem = Array.from(modeItems).find(i => i.dataset.mode === currentMode); + if (activeModeItem) { + currentModeBadge.textContent = activeModeItem.querySelector('span').textContent; + } + + // Render messages + chatWindow.innerHTML = ''; + data.messages.forEach(msg => { + appendMessage(msg.role, msg.content, false); // false = don't animate existing + + // Special handling for game/app mode launch buttons + if ((currentMode === 'game' || currentMode === 'app') && msg.role === 'assistant') { + addLaunchButton(msg.content); + } + }); + + // Highlight active history item + document.querySelectorAll('.history-item').forEach(i => { + if (i.dataset.id == chatId) i.classList.add('active'); + else i.classList.remove('active'); + }); + + chatWindow.scrollTop = chatWindow.scrollHeight; + } + } catch (e) { + console.error(e); + chatWindow.innerHTML = '
Failed to load chat
'; + } + } + + async function deleteChat(chatId) { + if (!confirm('Are you sure you want to delete this chat?')) return; + + try { + const resp = await fetch(`api/history.php?action=delete&chat_id=${chatId}`); + const data = await resp.json(); + if (data.success) { + if (currentChatId == chatId) startNewChat(); + loadHistory(); + } + } catch (e) { + console.error(e); + } + } + // --- Chat Logic --- async function sendMessage() { const message = chatInput.value.trim(); if (!message) return; + const isNewChat = !currentChatId; + // Clear input and disable chatInput.value = ''; chatInput.style.height = 'auto'; @@ -78,6 +196,11 @@ document.addEventListener('DOMContentLoaded', () => { if (currentMode === 'game' || currentMode === 'app') { addLaunchButton(data.message); } + + // If it was a new chat, refresh history to show the title + if (isNewChat) { + loadHistory(); + } } else { appendMessage('assistant', 'Error: ' + (data.error || 'Unknown error')); } @@ -88,15 +211,16 @@ document.addEventListener('DOMContentLoaded', () => { } } - function appendMessage(role, text) { + function appendMessage(role, text, animate = true) { + if (role === 'system') return; + // Remove empty state if present const emptyState = chatWindow.querySelector('.my-auto'); if (emptyState) emptyState.remove(); const msgDiv = document.createElement('div'); - msgDiv.className = `message message-${role} animate-fade-in`; + msgDiv.className = `message message-${role} ${animate ? 'animate-fade-in' : ''}`; - // Use marked.js or simple formatting msgDiv.innerHTML = formatText(text); chatWindow.appendChild(msgDiv); @@ -104,24 +228,19 @@ document.addEventListener('DOMContentLoaded', () => { } function formatText(text) { - // Handle code blocks with more flexibility let formatted = text; - // Escape HTML for non-code parts - // This is tricky without a library, let's just do code blocks first - // Code blocks: ```[lang]\n[code]``` formatted = formatted.replace(/```(\w+)?\s*([\s\S]*?)```/g, (match, lang, code) => { + const safeCode = code.trim().replace(/`/g, '\`'); return `
${lang || 'code'} - Copy + Copy
${escapeHtml(code.trim())}
`; }); // Simple line breaks for non-code parts - // (Only for parts outside of the generated HTML above) - // This is a bit naive but works for simple chat if (!formatted.includes('
'); } @@ -136,11 +255,9 @@ document.addEventListener('DOMContentLoaded', () => { } function addLaunchButton(content) { - // Find code block content const match = content.match(/```(?:html|xml)?\s*([\s\S]*?)```/i); let codeToLaunch = match ? match[1] : content; - // Only add button if it looks like a full HTML document or contains significant HTML tags const hasHtmlTags = / { btn.className = 'btn btn-sm btn-success mt-2 d-inline-flex align-items-center gap-2 shadow-sm'; btn.innerHTML = ' Launch Application in New Tab'; btn.onclick = () => { - // If it's not a full HTML, wrap it if (!codeToLaunch.toLowerCase().includes('AI Generated App${codeToLaunch}`; } @@ -157,7 +273,6 @@ document.addEventListener('DOMContentLoaded', () => { window.open(url, '_blank'); }; - // Append to the last message div chatWindow.lastElementChild.appendChild(btn); } } @@ -181,7 +296,6 @@ document.addEventListener('DOMContentLoaded', () => { } }); - // Auto-resize textarea chatInput.addEventListener('input', () => { chatInput.style.height = 'auto'; chatInput.style.height = (chatInput.scrollHeight) + 'px'; @@ -222,7 +336,6 @@ document.addEventListener('DOMContentLoaded', () => { if (data.success) { const modal = bootstrap.Modal.getInstance(document.getElementById('settingsModal')); if (modal) modal.hide(); - showToast('Settings saved successfully!'); } } catch (e) { @@ -251,4 +364,7 @@ document.addEventListener('DOMContentLoaded', () => { const currentTheme = document.documentElement.getAttribute('data-theme'); const activeSwatch = document.querySelector(`.theme-swatch[data-theme="${currentTheme}"]`); if (activeSwatch) activeSwatch.classList.add('active'); -}); + + // Initial load + loadHistory(); +}); \ No newline at end of file diff --git a/index.php b/index.php index 7cb89f2..afe75f8 100644 --- a/index.php +++ b/index.php @@ -188,26 +188,6 @@ $limitsOff = $settings['limits_off'] ?? '0'; .modal-footer { border-top: 1px solid var(--border-color); } - - /* Themes Grid */ - .theme-grid { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 10px; - } - .theme-swatch { - height: 40px; - border-radius: 6px; - cursor: pointer; - border: 2px solid transparent; - display: flex; - align-items: center; - justify-content: center; - font-size: 0.8rem; - } - .theme-swatch.active { - border-color: var(--accent-color); - } @@ -240,14 +220,13 @@ $limitsOff = $settings['limits_off'] ?? '0';
Recent History
-
No recent chats
@@ -286,47 +265,56 @@ $limitsOff = $settings['limits_off'] ?? '0';