Compare commits

..

No commits in common. "ai-dev" and "master" have entirely different histories.

4 changed files with 143 additions and 446 deletions

View File

@ -1,67 +0,0 @@
<?php
declare(strict_types=1);
ini_set('display_errors', '0');
error_reporting(E_ALL);
header('Content-Type: application/json');
require_once __DIR__ . '/../ai/LocalAIApi.php';
// Get the user's message from the POST request
$input = json_decode(file_get_contents('php://input'), true);
$userMessage = $input['message'] ?? '';
if (empty($userMessage)) {
echo json_encode(['error' => 'Message is empty.']);
exit;
}
$aiReply = 'Sorry, I could not process your request at the moment.';
$responseSuccess = false;
try {
$systemPrompt = 'You are a friendly and helpful AI assistant for IBMR Festverse, a college event management platform. Your goal is to answer questions about events, help users discover fests, and provide information about the platform. Keep your answers concise and cheerful.';
// Create the payload for the AI API
$payload = [
'input' => [
['role' => 'system', 'content' => $systemPrompt],
['role' => 'user', 'content' => $userMessage],
],
];
// Options for the API call
$options = [
'poll_interval' => 5, // seconds
'poll_timeout' => 120 // seconds
];
// Call the AI service
$resp = LocalAIApi::createResponse($payload, $options);
if (!empty($resp['success'])) {
$text = LocalAIApi::extractText($resp);
if ($text !== '') {
$aiReply = $text;
$responseSuccess = true;
} else {
// Handle cases where AI gives a non-text response or empty text
$aiReply = 'I received a response, but it was empty. Can you try rephrasing?';
}
} else {
error_log('AI API Error: ' . ($resp['error'] ?? 'Unknown error'));
$aiReply = 'There was an issue connecting to the AI service. Please try again later.';
}
} catch (Exception $e) {
error_log('AI Chat Exception: ' . $e->getMessage());
$aiReply = 'A server error occurred. We are looking into it.';
}
if ($responseSuccess) {
echo json_encode(['reply' => $aiReply]);
} else {
// In case of an error, we still return a JSON response with a user-friendly message
// The specific error is logged on the server for debugging
echo json_encode(['reply' => $aiReply]);
}

View File

@ -1,200 +0,0 @@
:root {
--bg-color: #0D1117;
--surface-color: #161B22;
--border-color: #30363d;
--primary-gradient-start: #38BDF8;
--primary-gradient-end: #818CF8;
--accent-color: #F59E0B;
--text-primary: #E6EDF3;
--text-secondary: #7D8590;
--font-family-sans-serif: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
body {
background-color: var(--bg-color);
color: var(--text-primary);
font-family: var(--font-family-sans-serif);
min-height: 100vh;
}
.navbar {
background-color: transparent;
padding: 1rem 0;
}
.navbar-brand {
font-weight: 700;
font-size: 1.5rem;
background: linear-gradient(45deg, var(--primary-gradient-start), var(--primary-gradient-end));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
color: transparent;
}
.nav-link {
color: var(--text-secondary);
font-weight: 500;
transition: color 0.2s ease-in-out;
}
.nav-link:hover, .nav-link.active {
color: var(--text-primary);
}
.navbar-toggler {
border: none;
color: var(--text-primary);
font-size: 1.5rem;
}
.navbar-toggler:focus {
box-shadow: none;
}
.hero-section {
padding: 8rem 0;
animation: fadeIn 1s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.hero-title {
font-weight: 700;
color: var(--text-primary);
letter-spacing: -1.5px;
}
.hero-subtitle {
color: var(--text-secondary);
max-width: 600px;
margin: 1.5rem auto;
}
.btn-primary {
background: linear-gradient(45deg, var(--primary-gradient-start), var(--primary-gradient-end));
border: none;
padding: 0.75rem 2rem;
font-weight: 500;
transition: transform 0.2s ease-out, box-shadow 0.2s ease-out;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}
/* Chat Widget */
#chat-widget-container {
position: fixed;
bottom: 2rem;
right: 2rem;
z-index: 1050;
}
#chat-toggle-button {
width: 60px;
height: 60px;
font-size: 1.8rem;
background: linear-gradient(45deg, var(--primary-gradient-start), var(--primary-gradient-end));
color: white;
border: none;
display: flex;
justify-content: center;
align-items: center;
}
#chat-window {
display: none;
width: 370px;
height: 70vh;
max-height: 600px;
flex-direction: column;
background-color: var(--surface-color);
border: 1px solid var(--border-color);
color: var(--text-primary);
position: absolute;
bottom: 0;
right: 0;
}
#chat-window.open {
display: flex;
animation: slideUp 0.3s ease-out;
}
@keyframes slideUp {
from { transform: translateY(30px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
#chat-window .card-header {
background-color: var(--surface-color);
border-bottom: 1px solid var(--border-color);
}
#chat-window .card-header .ai-avatar {
width: 32px;
height: 32px;
border-radius: 50%;
background: linear-gradient(45deg, var(--primary-gradient-start), var(--primary-gradient-end));
color: white;
display: flex;
align-items: center;
justify-content: center;
}
#chat-window .card-footer {
background-color: var(--surface-color);
border-top: 1px solid var(--border-color);
}
#chat-messages {
flex-grow: 1;
overflow-y: auto;
padding: 1rem;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.message {
max-width: 85%;
padding: 0.5rem 1rem;
border-radius: 1.25rem;
display: inline-block;
}
.message.received {
background-color: #21262d;
align-self: flex-start;
border-bottom-left-radius: 0.25rem;
}
.message.sent {
background: linear-gradient(45deg, var(--primary-gradient-start), var(--primary-gradient-end));
color: white;
align-self: flex-end;
border-bottom-right-radius: 0.25rem;
}
.message .message-content {
margin: 0;
word-wrap: break-word;
}
.message.typing {
color: var(--text-secondary);
font-style: italic;
align-self: flex-start;
}
#chat-input {
background-color: #0D1117;
border: 1px solid var(--border-color);
color: var(--text-primary);
}
#chat-input:focus {
background-color: #0D1117;
color: var(--text-primary);
box-shadow: none;
border-color: var(--primary-gradient-end);
}

View File

@ -1,87 +0,0 @@
document.addEventListener('DOMContentLoaded', function () {
const chatWindow = document.getElementById('chat-window');
const chatToggleButton = document.getElementById('chat-toggle-button');
const chatCloseButton = document.getElementById('chat-close-button');
const chatForm = document.getElementById('chat-form');
const chatInput = document.getElementById('chat-input');
const chatMessages = document.getElementById('chat-messages');
const toggleChat = (forceState) => {
const isOpen = chatWindow.classList.contains('open');
const show = forceState !== undefined ? forceState : !isOpen;
if (show) {
chatWindow.classList.add('open');
chatToggleButton.style.display = 'none';
} else {
chatWindow.classList.remove('open');
chatToggleButton.style.display = 'flex';
}
};
chatToggleButton.addEventListener('click', () => toggleChat(true));
chatCloseButton.addEventListener('click', () => toggleChat(false));
const addMessage = (text, type, isTyping = false) => {
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', type);
const contentDiv = document.createElement('div');
contentDiv.classList.add('message-content');
contentDiv.textContent = text;
messageDiv.appendChild(contentDiv);
if (isTyping) {
messageDiv.id = 'typing-indicator';
messageDiv.classList.add('typing');
}
chatMessages.appendChild(messageDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
return messageDiv;
};
chatForm.addEventListener('submit', async (e) => {
e.preventDefault();
const userInput = chatInput.value.trim();
if (!userInput) return;
addMessage(userInput, 'sent');
chatInput.value = '';
chatInput.disabled = true;
const typingIndicator = addMessage('Festverse AI is typing...', 'received', true);
try {
const response = await fetch('api/ai_chat.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ message: userInput }),
});
if (!response.ok) {
throw new Error('Network response was not ok.');
}
const data = await response.json();
typingIndicator.remove();
if (data.reply) {
addMessage(data.reply, 'received');
} else {
addMessage('Sorry, I encountered an error. Please try again.', 'received');
}
} catch (error) {
console.error('Chat error:', error);
typingIndicator.remove();
addMessage('Sorry, I could not connect to the AI assistant.', 'received');
} finally {
chatInput.disabled = false;
chatInput.focus();
}
});
});

235
index.php
View File

@ -1,99 +1,150 @@
<?php
declare(strict_types=1);
@ini_set('display_errors', '1');
@error_reporting(E_ALL);
@date_default_timezone_set('UTC');
$phpVersion = PHP_VERSION;
$now = date('Y-m-d H:i:s');
?>
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>IBMR Festverse - Your College Event Universe</title> <title>New Style</title>
<?php
<?php // Read project preview data from environment
// Read project preview data from environment $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'IBMR Festverse is a college event management platform with AI features.'; $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; ?>
?> <?php if ($projectDescription): ?>
<?php if ($projectDescription): ?> <!-- Meta description -->
<!-- Meta description --> <meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
<meta name="description" content="<?= htmlspecialchars($projectDescription) ?>" /> <!-- Open Graph meta tags -->
<!-- Open Graph meta tags --> <meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" /> <!-- Twitter meta tags -->
<!-- Twitter meta tags --> <meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" /> <?php endif; ?>
<?php endif; ?> <?php if ($projectImageUrl): ?>
<?php if ($projectImageUrl): ?> <!-- Open Graph image -->
<!-- Open Graph image --> <meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" /> <!-- Twitter image -->
<!-- Twitter image --> <meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" /> <?php endif; ?>
<?php endif; ?> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<meta property="og:title" content="IBMR Festverse" /> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
<meta property="twitter:title" content="IBMR Festverse" /> <style>
:root {
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> --bg-color-start: #6a11cb;
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"> --bg-color-end: #2575fc;
<link rel="preconnect" href="https://fonts.googleapis.com"> --text-color: #ffffff;
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> --card-bg-color: rgba(255, 255, 255, 0.01);
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet"> --card-border-color: rgba(255, 255, 255, 0.1);
<link rel="stylesheet" href="assets/css/custom.css"> }
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% { background-position: 0% 0%; }
100% { background-position: 100% 100%; }
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
}
.loader {
margin: 1.25rem auto 1.25rem;
width: 48px;
height: 48px;
border: 3px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.hint {
opacity: 0.9;
}
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap; border: 0;
}
h1 {
font-size: 3rem;
font-weight: 700;
margin: 0 0 1rem;
letter-spacing: -1px;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
}
code {
background: rgba(0,0,0,0.2);
padding: 2px 6px;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
footer {
position: absolute;
bottom: 1rem;
font-size: 0.8rem;
opacity: 0.7;
}
</style>
</head> </head>
<body> <body>
<main>
<header class="navbar navbar-expand-lg"> <div class="card">
<div class="container"> <h1>Analyzing your requirements and generating your website…</h1>
<a class="navbar-brand" href="#">IBMR Festverse</a> <div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <span class="sr-only">Loading…</span>
<i class="bi bi-list"></i> </div>
</button> <p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
<div class="collapse navbar-collapse" id="navbarNav"> <p class="hint">This page will update automatically as the plan is implemented.</p>
<ul class="navbar-nav ms-auto"> <p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
<li class="nav-item"><a class="nav-link active" href="#">Home</a></li>
<li class="nav-item"><a class="nav-link" href="#">Events</a></li>
<li class="nav-item"><a class="nav-link" href="#">Help</a></li>
</ul>
</div>
</div>
</header>
<main class="container">
<div class="hero-section text-center">
<h1 class="hero-title display-3">Discover Your Next College Experience</h1>
<p class="hero-subtitle lead">The ultimate platform for college fests, workshops, and events, supercharged with AI.</p>
<a href="#" class="btn btn-primary btn-lg rounded-pill">Explore Events</a>
</div>
</main>
<!-- Chat Widget -->
<div id="chat-widget-container">
<button id="chat-toggle-button" class="btn rounded-pill shadow-lg">
<i class="bi bi-chat-dots-fill"></i>
</button>
<div id="chat-window" class="card shadow-lg rounded-4">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="d-flex align-items-center">
<div class="ai-avatar">
<i class="bi bi-robot"></i>
</div>
<h5 class="mb-0 ms-2">Festverse AI</h5>
</div>
<button id="chat-close-button" type="button" class="btn-close"></button>
</div>
<div class="card-body" id="chat-messages">
<div class="message received">
<div class="message-content">Hello! How can I help you find the perfect event today?</div>
</div>
</div>
<div class="card-footer">
<form id="chat-form" class="d-flex">
<input type="text" id="chat-input" class="form-control" placeholder="Ask about events, schedules..." autocomplete="off">
<button type="submit" class="btn btn-primary ms-2 rounded-pill">
<i class="bi bi-send-fill"></i>
</button>
</form>
</div>
</div>
</div> </div>
<!-- End Chat Widget --> </main>
<footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> Page updated: <?= htmlspecialchars($now) ?> (UTC)
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script> </footer>
</body> </body>
</html> </html>