nov 20th, 2025 V.2

This commit is contained in:
Flatlogic Bot 2025-11-20 05:18:32 +00:00
parent e6fd5f2ecb
commit aab4f05548

231
chat.php
View File

@ -10,117 +10,153 @@ if (!is_logged_in()) {
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- SEO & Meta Tags -->
<title>AI Chat - FinMox</title> <title>AI Chat - FinMox</title>
<meta name="description" content="FinMox Flow - a multi-tenant SaaS platform for HR and Operations teams. Built with Flatlogic Generator."> <script src="https://cdn.tailwindcss.com"></script>
<meta name="keywords" content="finmox, hr, operations, saas, candidate tracking, onboarding, automations, ai copilot, flatlogic"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<!-- Social Media Meta Tags -->
<meta property="og:title" content="FinMox Flow">
<meta property="og:description" content="A multi-tenant SaaS platform for HR and Operations teams.">
<meta property="og:image" content="<?php echo htmlspecialchars($_SERVER['PROJECT_IMAGE_URL'] ?? '', ENT_QUOTES, 'UTF-8'); ?>">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="<?php echo htmlspecialchars($_SERVER['PROJECT_IMAGE_URL'] ?? '', ENT_QUOTES, 'UTF-8'); ?>">
<!-- Stylesheets -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
<style> <style>
#chat-container { @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
max-width: 800px; * {
margin: 2rem auto; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
border: 1px solid #ddd;
border-radius: 8px;
padding: 1rem;
height: 70vh;
display: flex;
flex-direction: column;
} }
#chat-messages { body {
flex-grow: 1; -webkit-font-smoothing: antialiased;
overflow-y: auto;
padding: 1rem;
border-bottom: 1px solid #ddd;
} }
.message { .chat-container {
margin-bottom: 1rem; height: calc(100vh - 80px);
} }
.message .sender { .message-bubble {
font-weight: bold; max-width: 75%;
} }
.message .content { .user-message {
padding: 0.5rem 1rem; background-color: #3B82F6;
border-radius: 8px; color: white;
display: inline-block;
} }
.user-message .content { .ai-message {
background-color: #e9f5ff; background-color: #E5E7EB;
color: #1F2937;
} }
.ai-message .content { #chat-input:focus {
background-color: #f8f9fa; outline: none;
box-shadow: none;
border-color: #3B82F6;
} }
</style> </style>
</head> </head>
<body> <body class="bg-gray-100">
<div class="flex h-screen">
<header class="header d-flex justify-content-between align-items-center"> <!-- Sidebar -->
<div class="logo"> <div class="w-1/4 bg-white border-r border-gray-200 flex flex-col">
<a href="app.php"> <div class="p-4 border-b border-gray-200">
<img src="assets/pasted-20251120-051320-b2b0cdfa.png" alt="FinMox Logo" style="height: 32px;"> <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">
</a> <i class="fas fa-plus"></i>
</div> New Chat
<nav class="d-flex align-items-center"> </a>
<a href="app.php" class="btn btn-outline-primary me-2">Home</a>
<a href="chat.php" class="btn btn-outline-primary me-2">Chat</a>
<a href="dashboard.php" class="btn btn-outline-primary me-2">Dashboard</a>
<a href="workflows.php" class="btn btn-outline-primary me-3">Workflows</a>
<div class="dropdown">
<button class="btn btn-outline-secondary dropdown-toggle" type="button" id="userDropdown" data-bs-toggle="dropdown" aria-expanded="false">
<?php echo htmlspecialchars($_SESSION['username']); ?>
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
<?php if (hasPermission('manage_roles')): ?>
<li><a class="dropdown-item" href="roles.php">Manage Roles</a></li>
<li><hr class="dropdown-divider"></li>
<?php endif; ?>
<li><a class="dropdown-item" href="logout.php">Logout</a></li>
</ul>
</div> </div>
</nav> <div class="flex-grow overflow-y-auto">
</header> <!-- Conversation List -->
<div class="p-4">
<main class="main-content"> <h2 class="text-xs text-gray-500 font-semibold uppercase mb-2">Past Conversations</h2>
<div id="chat-container"> <ul id="conversation-list">
<div id="chat-messages"></div> <!-- Placeholder for conversation items -->
<div class="input-group mt-3"> <li class="p-2 rounded-lg hover:bg-gray-100 cursor-pointer">
<input type="text" id="user-input" class="form-control" placeholder="Ask the AI Assistant..."> <p class="font-semibold text-sm truncate">Onboarding Workflow Ideas</p>
<button id="send-btn" class="btn btn-primary">Send</button> <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>
</div> </div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> <!-- 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="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> <script>
const chatMessages = document.getElementById('chat-messages'); const chatMessages = document.getElementById('chat-messages');
const userInput = document.getElementById('user-input'); const userInput = document.getElementById('chat-input');
const sendBtn = document.getElementById('send-btn'); const sendBtn = document.getElementById('send-btn');
const typingIndicator = document.getElementById('typing-indicator');
const charCounter = document.getElementById('char-counter');
function addMessage(sender, content) { function addMessage(sender, content) {
const messageDiv = document.createElement('div'); const messageWrapper = document.createElement('div');
messageDiv.classList.add('message', sender + '-message'); 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 senderDiv = document.createElement('div'); const messageBubble = document.createElement('div');
senderDiv.classList.add('sender'); messageBubble.classList.add('p-3', 'rounded-lg', 'message-bubble');
senderDiv.textContent = sender === 'user' ? 'You' : 'AI Assistant';
const contentDiv = document.createElement('div'); const timestamp = document.createElement('div');
contentDiv.classList.add('content'); timestamp.classList.add('text-xs', 'text-gray-400', 'mt-1');
contentDiv.textContent = content; timestamp.textContent = new Date().toLocaleTimeString();
messageDiv.appendChild(senderDiv); if (sender === 'user') {
messageDiv.appendChild(contentDiv); messageWrapper.classList.add('justify-end');
chatMessages.appendChild(messageDiv); 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; chatMessages.scrollTop = chatMessages.scrollHeight;
} }
@ -130,7 +166,9 @@ if (!is_logged_in()) {
addMessage('user', message); addMessage('user', message);
userInput.value = ''; userInput.value = '';
charCounter.textContent = '0 / 4000';
sendBtn.disabled = true; sendBtn.disabled = true;
typingIndicator.classList.remove('hidden');
try { try {
const response = await fetch('api/chat.php', { const response = await fetch('api/chat.php', {
@ -154,15 +192,28 @@ if (!is_logged_in()) {
addMessage('ai', 'Sorry, something went wrong. Please check the console.'); addMessage('ai', 'Sorry, something went wrong. Please check the console.');
} finally { } finally {
sendBtn.disabled = false; sendBtn.disabled = false;
typingIndicator.classList.add('hidden');
} }
} }
sendBtn.addEventListener('click', sendMessage); sendBtn.addEventListener('click', sendMessage);
userInput.addEventListener('keypress', (e) => { userInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') { if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage(); 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> </script>
</body> </body>
</html> </html>