221 lines
9.4 KiB
PHP
221 lines
9.4 KiB
PHP
<?php
|
|
require_once 'auth.php';
|
|
if (!is_logged_in()) {
|
|
header('Location: login.php');
|
|
exit();
|
|
}
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>AI Chat - FinMox</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
|
<style>
|
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
|
|
* {
|
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
}
|
|
body {
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
.chat-container {
|
|
height: calc(100vh - 80px);
|
|
}
|
|
.message-bubble {
|
|
max-width: 75%;
|
|
}
|
|
.user-message {
|
|
background-color: #3B82F6;
|
|
color: white;
|
|
}
|
|
.ai-message {
|
|
background-color: #E5E7EB;
|
|
color: #1F2937;
|
|
}
|
|
#chat-input:focus {
|
|
outline: none;
|
|
box-shadow: none;
|
|
border-color: #3B82F6;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="bg-gray-100">
|
|
<div class="flex h-screen">
|
|
<!-- Sidebar -->
|
|
<div class="w-1/4 bg-white border-r border-gray-200 flex flex-col">
|
|
<div class="p-4 border-b border-gray-200">
|
|
<a href="chat.php" class="w-full bg-black text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center justify-center gap-2">
|
|
<i class="fas fa-plus"></i>
|
|
New Chat
|
|
</a>
|
|
</div>
|
|
<div class="flex-grow overflow-y-auto">
|
|
<!-- Conversation List -->
|
|
<div class="p-4">
|
|
<h2 class="text-xs text-gray-500 font-semibold uppercase mb-2">Past Conversations</h2>
|
|
<ul id="conversation-list">
|
|
<!-- Placeholder for conversation items -->
|
|
<li class="p-2 rounded-lg hover:bg-gray-100 cursor-pointer">
|
|
<p class="font-semibold text-sm truncate">Onboarding Workflow Ideas</p>
|
|
<p class="text-xs text-gray-500 truncate">Sure, here are some ideas for your onboarding...</p>
|
|
<p class="text-xs text-gray-400 mt-1">2 hours ago</p>
|
|
</li>
|
|
<li class="p-2 rounded-lg hover:bg-gray-100 cursor-pointer mt-2">
|
|
<p class="font-semibold text-sm truncate">Compliance Questions</p>
|
|
<p class="text-xs text-gray-500 truncate">Let's break down the compliance requirements...</p>
|
|
<p class="text-xs text-gray-400 mt-1">Yesterday</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Main Chat Area -->
|
|
<div class="w-3/4 flex flex-col">
|
|
<header class="bg-white border-b border-gray-200 p-4 flex items-center justify-between">
|
|
<div class="flex items-center gap-2">
|
|
<a href="app.php">
|
|
<img src="assets/pasted-20251120-051320-b2b0cdfa.png" alt="FinMox Logo" style="height: 32px;">
|
|
</a>
|
|
</div>
|
|
<nav class="flex items-center gap-4">
|
|
<a href="app.php" class="text-sm text-gray-600 hover:text-gray-900">Home</a>
|
|
<a href="dashboard.php" class="text-sm text-gray-600 hover:text-gray-900">Dashboard</a>
|
|
<a href="workflows.php" class="text-sm text-gray-600 hover:text-gray-900">Workflows</a>
|
|
<a href="settings.php" class="text-sm text-gray-600 hover:text-gray-900">Settings</a>
|
|
<a href="logout.php" class="text-sm text-gray-600 hover:text-gray-900">Logout</a>
|
|
</nav>
|
|
</header>
|
|
|
|
<main class="flex-grow p-6 overflow-y-auto" id="chat-messages">
|
|
<!-- Messages will be appended here -->
|
|
</main>
|
|
|
|
<div class="bg-white border-t border-gray-200 p-4">
|
|
<div class="typing-indicator text-sm text-gray-500 mb-2 hidden" id="typing-indicator">
|
|
AI is thinking...
|
|
</div>
|
|
<div class="relative">
|
|
<textarea id="chat-input" class="w-full border border-gray-300 rounded-lg p-4 pr-28" placeholder="Ask the AI Assistant..." rows="1"></textarea>
|
|
<div class="absolute bottom-3 right-3 flex items-center">
|
|
<button class="mr-2 text-gray-400 hover:text-gray-600">
|
|
<i class="fas fa-paperclip"></i>
|
|
</button>
|
|
<button id="send-btn" class="bg-black text-white px-4 py-2 rounded-lg text-sm font-medium">Send</button>
|
|
</div>
|
|
</div>
|
|
<div class="text-xs text-gray-400 mt-1 text-right" id="char-counter">0 / 4000</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const chatMessages = document.getElementById('chat-messages');
|
|
const userInput = document.getElementById('chat-input');
|
|
const sendBtn = document.getElementById('send-btn');
|
|
const typingIndicator = document.getElementById('typing-indicator');
|
|
const charCounter = document.getElementById('char-counter');
|
|
|
|
function addMessage(sender, content) {
|
|
const messageWrapper = document.createElement('div');
|
|
messageWrapper.classList.add('flex', 'mb-4');
|
|
|
|
const avatar = document.createElement('div');
|
|
avatar.classList.add('w-8', 'h-8', 'rounded-full', 'flex', 'items-center', 'justify-center', 'text-white', 'font-bold');
|
|
|
|
const messageBubble = document.createElement('div');
|
|
messageBubble.classList.add('p-3', 'rounded-lg', 'message-bubble');
|
|
|
|
const timestamp = document.createElement('div');
|
|
timestamp.classList.add('text-xs', 'text-gray-400', 'mt-1');
|
|
timestamp.textContent = new Date().toLocaleTimeString();
|
|
|
|
if (sender === 'user') {
|
|
messageWrapper.classList.add('justify-end');
|
|
avatar.classList.add('bg-blue-500', 'ml-3');
|
|
avatar.textContent = 'U';
|
|
messageBubble.classList.add('user-message');
|
|
messageBubble.textContent = content;
|
|
messageWrapper.appendChild(messageBubble);
|
|
messageWrapper.appendChild(avatar);
|
|
} else {
|
|
messageWrapper.classList.add('justify-start');
|
|
avatar.classList.add('bg-gray-700', 'mr-3');
|
|
avatar.textContent = 'AI';
|
|
messageBubble.classList.add('ai-message');
|
|
messageBubble.innerHTML = content; // Use innerHTML to render potential markdown
|
|
messageWrapper.appendChild(avatar);
|
|
messageWrapper.appendChild(messageBubble);
|
|
}
|
|
|
|
const messageContainer = document.createElement('div');
|
|
messageContainer.classList.add('flex', 'flex-col', (sender === 'user' ? 'items-end' : 'items-start'));
|
|
messageContainer.appendChild(messageBubble);
|
|
messageContainer.appendChild(timestamp);
|
|
|
|
messageWrapper.appendChild(messageContainer);
|
|
chatMessages.appendChild(messageWrapper);
|
|
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
}
|
|
|
|
async function sendMessage() {
|
|
const message = userInput.value.trim();
|
|
if (!message) return;
|
|
|
|
addMessage('user', message);
|
|
userInput.value = '';
|
|
charCounter.textContent = '0 / 4000';
|
|
sendBtn.disabled = true;
|
|
typingIndicator.classList.remove('hidden');
|
|
|
|
try {
|
|
const response = await fetch('api/chat.php', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ message })
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
|
|
const data = await response.json();
|
|
const aiReply = data.reply || data.error || 'No reply from AI.';
|
|
addMessage('ai', aiReply);
|
|
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
addMessage('ai', 'Sorry, something went wrong. Please check the console.');
|
|
} finally {
|
|
sendBtn.disabled = false;
|
|
typingIndicator.classList.add('hidden');
|
|
}
|
|
}
|
|
|
|
sendBtn.addEventListener('click', sendMessage);
|
|
userInput.addEventListener('keypress', (e) => {
|
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
e.preventDefault();
|
|
sendMessage();
|
|
}
|
|
});
|
|
|
|
userInput.addEventListener('input', () => {
|
|
const count = userInput.value.length;
|
|
charCounter.textContent = `${count} / 4000`;
|
|
});
|
|
|
|
// Auto-resize textarea
|
|
userInput.addEventListener('input', () => {
|
|
userInput.style.height = 'auto';
|
|
userInput.style.height = (userInput.scrollHeight) + 'px';
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|