๐ Source: index.php
<?php
session_start();
require_once 'vendor/autoload.php';
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
$host = $_SERVER['HTTP_HOST'];
$baseUrl = "http://createcraftweb.playit.plus/AgentAI";
$client = new Google\Client();
$client->setClientId('1082083393389-c5uekspcp2boc1gd0n0gr3v1a5vbb3jg.apps.googleusercontent.com');
$client->setClientSecret('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');
$client->setRedirectUri("http://createcraftweb.playit.plus/AgentAI/oauth2callback.php");
$client->addScope('https://www.googleapis.com/auth/gmail.readonly');
$client->setAccessType('offline');
$client->setPrompt('consent');
$isMobile = preg_match('/(android|iphone|ipad|mobile)/i', $_SERVER['HTTP_USER_AGENT']);
$lang = $_COOKIE['inboxzero_lang'] ?? 'en';
?>
<!DOCTYPE html>
<html lang="<?php echo $lang; ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>InboxZero AI - Email Assistant</title>
<link rel="stylesheet" href="style.css">
</head>
<body data-theme="light">
<div class="container">
<div class="header">
<div class="header-top">
<h1>๐ง InboxZero AI <span class="badge">v2.0</span></h1>
<div class="controls">
<button class="theme-toggle" onclick="toggleTheme()" id="themeBtn">๐ Dark</button>
<select class="lang-select" id="langSelect" onchange="changeLanguage()">
<option value="en" <?php echo $lang == 'en' ? 'selected' : ''; ?>>๐ฌ๐ง English</option>
<option value="ro" <?php echo $lang == 'ro' ? 'selected' : ''; ?>>๐ท๐ด Romรขnฤ</option>
</select>
</div>
</div>
<p id="headerDescription">Your intelligent email assistant - ask anything about your inbox</p>
<div class="status">๐ง <?php echo date('Y-m-d H:i:s'); ?></div>
</div>
<div class="content">
<div class="sidebar">
<!-- Chat History Section -->
<div class="chat-history-section">
<h3>๐ฌ Recent Chats</h3>
<div id="chatHistoryList" class="chat-history-list"></div>
<button onclick="newChat()" class="new-chat-btn" id="newChatBtn">+ New Chat</button>
</div>
<hr>
<h3 id="inboxTitle">๐ฌ Your Inbox</h3>
<?php if (isset($_SESSION['access_token'])): ?>
<button onclick="logout()" class="logout-btn" id="logoutBtn">๐ช Logout</button>
<div id="emailList" style="margin-top: 15px;">
<div class="loading" id="loadingEmails">๐ฅ Loading your emails...</div>
</div>
<?php else: ?>
<p id="loginPrompt">๐ Login to access your Gmail inbox</p>
<?php
$authUrl = $client->createAuthUrl();
if ($isMobile) {
$authUrl .= '&device_id=mobile_' . md5($_SERVER['REMOTE_ADDR']) . '&device_name=MobileBrowser';
}
?>
<a href="<?php echo $authUrl; ?>" class="login-btn" id="loginBtn">๐ Sign in with Google</a>
<p style="font-size: 12px; margin-top: 15px;">
<small id="privacyNote">This app only reads your email metadata. No data is stored permanently.</small>
</p>
<?php endif; ?>
</div>
<div class="chat-area">
<div class="messages" id="messages">
<div class="message ai-message" id="welcomeMessage">
๐ค <strong>Hello! I'm InboxZero AI.</strong><br><br>
I can help you:<br>
โข ๐ Summarize unread emails<br>
โข ๐ Find specific messages<br>
โข ๐
Extract important dates<br>
โข โก Answer questions about your inbox<br><br>
<em>Try: "Show me emails from Steam" or "Do I have emails from ChatGPT?"</em>
</div>
</div>
<?php if (isset($_SESSION['access_token'])): ?>
<div class="input-area">
<textarea id="userInput" placeholder="Ask about your emails..." rows="1" onkeypress="if(event.key==='Enter' && !event.shiftKey) { event.preventDefault(); sendMessage(); }" style="overflow-y: hidden; resize: none;"></textarea>
<button onclick="sendMessage()" id="sendBtn">๐ค Send</button>
</div>
<?php endif; ?>
</div>
</div>
</div>
<script>
const translations = {
en: {
headerDesc: "Your intelligent email assistant - ask anything about your inbox",
inboxTitle: "๐ฌ Your Inbox",
logoutBtn: "๐ช Logout",
loadingEmails: "๐ฅ Loading your emails...",
loginPrompt: "๐ Login to access your Gmail inbox",
loginBtn: "๐ Sign in with Google",
privacyNote: "This app only reads your email metadata. No data is stored permanently.",
welcomeMsg: "๐ค <strong>Hello! I'm InboxZero AI.</strong><br><br>I can help you:<br>โข ๐ Summarize unread emails<br>โข ๐ Find specific messages<br>โข ๐
Extract important dates<br>โข โก Answer questions about your emails<br><br><em>Try: \"Show me emails from Steam\" or \"Do I have emails from ChatGPT?\"</em>",
inputPlaceholder: "Ask about your emails...",
sendBtn: "๐ค Send",
thinking: "๐ค Thinking...",
error: "โ Error: ",
noEmailsDetail: "๐ญ No emails found in your inbox",
failedToLoad: "โ Failed to load emails",
newChatBtn: "+ New Chat"
},
ro: {
headerDesc: "Asistentul tฤu inteligent pentru emailuri - รฎntreabฤ orice despre inbox",
inboxTitle: "๐ฌ Inbox-ul Tฤu",
logoutBtn: "๐ช Deconectare",
loadingEmails: "๐ฅ Se รฎncarcฤ emailurile...",
loginPrompt: "๐ Autentificฤ-te pentru a accesa Gmail",
loginBtn: "๐ Conectare cu Google",
privacyNote: "Aplicaศia citeศte doar metadatele emailurilor. Nu stocheazฤ date permanent.",
welcomeMsg: "๐ค <strong>Salut! Sunt InboxZero AI.</strong><br><br>Te pot ajuta:<br>โข ๐ Rezumatul emailurilor necitite<br>โข ๐ Gฤsirea mesajelor specifice<br>โข ๐
Extragerea datelor importante<br>โข โก Rฤspuns la รฎntrebฤri despre emailurile tale<br><br><em>รncearcฤ: \"Aratฤ-mi emailurile de la Steam\" sau \"Am emailuri de la ChatGPT?\"</em>",
inputPlaceholder: "รntreabฤ despre emailurile tale...",
sendBtn: "๐ค Trimite",
thinking: "๐ค Analizez inbox-ul...",
error: "โ Eroare: ",
noEmailsDetail: "๐ญ Nu s-au gฤsit emailuri รฎn inbox",
failedToLoad: "โ Nu s-au putut รฎncฤrca emailurile",
newChatBtn: "+ Chat Nou"
}
};
let currentLang = '<?php echo $lang; ?>';
let currentEmails = [];
let currentConversationId = null;
let reminderTimeout = null;
function updateLanguage() {
const t = translations[currentLang];
const headerDesc = document.getElementById('headerDescription');
if (headerDesc) headerDesc.innerText = t.headerDesc;
const inboxTitle = document.getElementById('inboxTitle');
if (inboxTitle) inboxTitle.innerText = t.inboxTitle;
const logoutBtn = document.getElementById('logoutBtn');
if (logoutBtn) logoutBtn.innerText = t.logoutBtn;
const loginPrompt = document.getElementById('loginPrompt');
if (loginPrompt) loginPrompt.innerText = t.loginPrompt;
const loginBtn = document.getElementById('loginBtn');
if (loginBtn) loginBtn.innerText = t.loginBtn;
const privacyNote = document.getElementById('privacyNote');
if (privacyNote) privacyNote.innerText = t.privacyNote;
const welcomeMessage = document.getElementById('welcomeMessage');
if (welcomeMessage) welcomeMessage.innerHTML = t.welcomeMsg;
const userInput = document.getElementById('userInput');
if (userInput) userInput.placeholder = t.inputPlaceholder;
const sendBtn = document.getElementById('sendBtn');
if (sendBtn) sendBtn.innerText = t.sendBtn;
const newChatBtn = document.getElementById('newChatBtn');
if (newChatBtn) newChatBtn.innerText = t.newChatBtn;
}
function changeLanguage() {
const select = document.getElementById('langSelect');
currentLang = select.value;
document.documentElement.lang = currentLang;
document.cookie = `inboxzero_lang=${currentLang}; path=/; max-age=${365 * 24 * 60 * 60}`;
updateLanguage();
}
function toggleTheme() {
const body = document.body;
const currentTheme = body.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
body.setAttribute('data-theme', newTheme);
localStorage.setItem('inboxzero_theme', newTheme);
const themeBtn = document.getElementById('themeBtn');
themeBtn.innerHTML = newTheme === 'dark' ? 'โ๏ธ Light' : '๐ Dark';
}
const savedTheme = localStorage.getItem('inboxzero_theme') || 'light';
document.body.setAttribute('data-theme', savedTheme);
const themeBtn = document.getElementById('themeBtn');
if (themeBtn) themeBtn.innerHTML = savedTheme === 'dark' ? 'โ๏ธ Light' : '๐ Dark';
function setReminder(text, minutes) {
if (reminderTimeout) clearTimeout(reminderTimeout);
addMessage('ai', `โฐ Reminder set for ${minutes} minute(s): "${text}"`);
reminderTimeout = setTimeout(() => {
if (Notification.permission === 'granted') {
new Notification('InboxZero Reminder', { body: text });
addMessage('ai', `๐ REMINDER: ${text}`);
} else if (Notification.permission !== 'denied') {
Notification.requestPermission().then(permission => {
if (permission === 'granted') {
new Notification('InboxZero Reminder', { body: text });
addMessage('ai', `๐ REMINDER: ${text}`);
}
});
}
}, minutes * 60 * 1000);
}
async function sendMessage() {
const input = document.getElementById('userInput');
const message = input.value.trim();
if (!message) return;
addMessage('user', message);
input.value = '';
input.disabled = true;
const t = translations[currentLang];
const thinkingMsg = addMessage('ai', t.thinking, true);
try {
const response = await fetch('chat_handler.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: message,
lang: currentLang,
conversation_id: currentConversationId
})
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
if (thinkingMsg) thinkingMsg.remove();
let reply = data.reply;
addMessage('ai', reply);
if (data.reminder) {
setReminder(data.reminder.text, data.reminder.minutes);
}
if (data.emails && data.emails.length > 0) {
currentEmails = data.emails;
displayEmails(currentEmails);
}
if (data.conversation_id && !currentConversationId) {
currentConversationId = data.conversation_id;
loadChatHistory();
}
} catch (error) {
if (thinkingMsg) thinkingMsg.remove();
console.error('Full error:', error);
addMessage('ai', t.error + error.message);
}
input.disabled = false;
input.focus();
}
function addMessage(role, text, returnElement = false, isHtml = false) {
const messagesDiv = document.getElementById('messages');
const messageDiv = document.createElement('div');
messageDiv.className = `message ${role === 'user' ? 'user-message' : 'ai-message'}`;
if (isHtml) {
messageDiv.innerHTML = role === 'user' ? `๐ค ${text}` : `๐ค ${text}`;
} else {
let formattedText = text.replace(/\n/g, '<br>');
messageDiv.innerHTML = role === 'user' ? `๐ค ${formattedText}` : `๐ค ${formattedText}`;
}
messagesDiv.appendChild(messageDiv);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
if (returnElement) return messageDiv;
return messageDiv;
}
async function loadEmails() {
const t = translations[currentLang];
try {
const response = await fetch('fetch_emails.php');
const emails = await response.json();
if (emails.error) {
document.getElementById('emailList').innerHTML = `<div class="loading">โ ${emails.error}</div>`;
} else if (emails.length === 0) {
document.getElementById('emailList').innerHTML = `<div class="loading">${t.noEmailsDetail}</div>`;
} else {
currentEmails = emails;
displayEmails(emails);
}
} catch (error) {
document.getElementById('emailList').innerHTML = `<div class="loading">${t.failedToLoad}</div>`;
}
}
function displayEmails(emails) {
if (!emails || emails.length === 0) {
document.getElementById('emailList').innerHTML = '<div class="loading">๐ญ No emails found</div>';
return;
}
let html = '<ul class="email-list">';
for (let i = 0; i < Math.min(emails.length, 10); i++) {
const email = emails[i];
const fromShort = email.from.length > 35 ? email.from.substring(0, 32) + '...' : email.from;
const subjectShort = email.subject.length > 45 ? email.subject.substring(0, 42) + '...' : email.subject;
html += `<li class="email-item" onclick="viewEmail('${email.id}', '${email.threadId}')">
<div class="email-from">๐จ ${escapeHtml(fromShort)}</div>
<div class="email-subject">${escapeHtml(subjectShort)}</div>
<div class="email-date">๐
${escapeHtml(email.date)}</div>
</li>`;
}
html += '</ul>';
document.getElementById('emailList').innerHTML = html;
}
async function getEmailLink(emailId, threadId) {
// Gmail web client URL format
const gmailUrl = `https://mail.google.com/mail/u/0/#inbox/${threadId}`;
return gmailUrl;
}
async function viewEmail(emailId, threadId) {
addMessage('ai', '๐ Opening email...');
try {
const response = await fetch('get_email.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email_id: emailId })
});
const data = await response.json();
if (data.content) {
let content = data.content;
if (content.includes('<a href')) {
addMessage('ai', content, false, true);
} else {
addMessage('ai', content);
}
// Add a "Open in Gmail" link
if (threadId) {
const gmailLink = `https://mail.google.com/mail/u/0/#inbox/${threadId}`;
addMessage('ai', `<a href="${gmailLink}" target="_blank" class="gmail-link">๐ง Open this email in Gmail โ</a>`, false, true);
}
} else {
addMessage('ai', 'โ Could not load email content.');
}
} catch (error) {
addMessage('ai', 'โ Failed to load email.');
}
}
async function newChat() {
try {
const response = await fetch('new_chat.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
const data = await response.json();
if (data.success) {
currentConversationId = data.chat_id;
const messagesDiv = document.getElementById('messages');
messagesDiv.innerHTML = '';
const welcomeMsg = document.createElement('div');
welcomeMsg.className = 'message ai-message';
welcomeMsg.id = 'welcomeMessage';
welcomeMsg.innerHTML = translations[currentLang].welcomeMsg;
messagesDiv.appendChild(welcomeMsg);
// Clear email list display (will reload)
document.getElementById('emailList').innerHTML = '<div class="loading">๐ฅ Loading your emails...</div>';
await loadEmails();
await loadChatHistory();
// Highlight the new chat in sidebar
const chatItems = document.querySelectorAll('.chat-history-item');
chatItems.forEach(item => item.classList.remove('active'));
}
} catch(e) {
console.error('New chat error:', e);
// Fallback: clear locally
currentConversationId = 'local_' + Date.now();
document.getElementById('messages').innerHTML = '';
const welcomeMsg = document.createElement('div');
welcomeMsg.className = 'message ai-message';
welcomeMsg.id = 'welcomeMessage';
welcomeMsg.innerHTML = translations[currentLang].welcomeMsg;
document.getElementById('messages').appendChild(welcomeMsg);
loadEmails();
}
}
async function loadChatHistory() {
try {
const response = await fetch('get_chats.php');
const chats = await response.json();
const container = document.getElementById('chatHistoryList');
if (container && !chats.error) {
if (chats.length === 0) {
container.innerHTML = '<div class="chat-history-item" style="opacity:0.6;">No previous chats</div>';
} else {
container.innerHTML = chats.map(chat => `
<div class="chat-history-item-wrapper">
<div class="chat-history-item ${currentConversationId == chat.id ? 'active' : ''}" onclick="switchChat(${chat.id})">
${escapeHtml(chat.title)}
</div>
<div class="chat-history-actions">
<button onclick="event.stopPropagation(); renameChat(${chat.id})" title="Rename">โ๏ธ</button>
<button onclick="event.stopPropagation(); deleteChat(${chat.id})" title="Delete">๐๏ธ</button>
</div>
</div>
`).join('');
}
}
} catch (e) {
console.error('Load chat history error:', e);
}
}
async function renameChat(chatId) {
const newTitle = prompt('Enter new chat name:');
if (newTitle && newTitle.trim()) {
await fetch('rename_chat.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ chat_id: chatId, title: newTitle.trim() })
});
loadChatHistory();
}
}
async function deleteChat(chatId) {
if (confirm('Delete this chat?')) {
await fetch('delete_chat.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ chat_id: chatId })
});
if (currentConversationId == chatId) {
currentConversationId = null;
document.getElementById('messages').innerHTML = '';
const welcomeMsg = document.createElement('div');
welcomeMsg.className = 'message ai-message';
welcomeMsg.innerHTML = translations[currentLang].welcomeMsg;
document.getElementById('messages').appendChild(welcomeMsg);
// Create a new chat automatically
const newChatResp = await fetch('new_chat.php', { method: 'POST' });
const newChatData = await newChatResp.json();
if (newChatData.success) {
currentConversationId = newChatData.chat_id;
}
}
loadChatHistory();
}
}
async function switchChat(chatId) {
currentConversationId = chatId;
try {
const response = await fetch('switch_chat.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ chat_id: chatId })
});
const data = await response.json();
if (data.messages) {
const messagesDiv = document.getElementById('messages');
messagesDiv.innerHTML = '';
// Display all messages from database
for (const msg of data.messages) {
addMessage(msg.role, msg.content);
}
// If no messages, show welcome
if (data.messages.length === 0) {
const welcomeMsg = document.createElement('div');
welcomeMsg.className = 'message ai-message';
welcomeMsg.id = 'welcomeMessage';
welcomeMsg.innerHTML = translations[currentLang].welcomeMsg;
messagesDiv.appendChild(welcomeMsg);
}
}
await loadChatHistory();
} catch (e) {
console.error('Switch chat error:', e);
window.location.reload();
}
}
function logout() {
fetch('logout.php').then(() => window.location.reload());
}
function escapeHtml(text) {
if (!text) return '';
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
const textarea = document.getElementById('userInput');
if (textarea) {
textarea.addEventListener('input', function() {
this.style.height = 'auto';
this.style.height = Math.min(this.scrollHeight, 100) + 'px';
});
}
if ('Notification' in window && Notification.permission !== 'denied' && Notification.permission !== 'granted') {
Notification.requestPermission();
}
updateLanguage();
<?php if (isset($_SESSION['access_token'])): ?>
window.onload = async function() {
await loadEmails();
await loadChatHistory();
// If no conversation exists, create one
if (!currentConversationId) {
const response = await fetch('new_chat.php', { method: 'POST' });
const data = await response.json();
if (data.success) {
currentConversationId = data.chat_id;
}
}
};
<?php endif; ?>
</script>
<style>
.chat-history-section {
margin-bottom: 15px;
}
.chat-history-list {
max-height: 150px;
overflow-y: auto;
margin-bottom: 8px;
}
.chat-history-item {
padding: 6px 10px;
margin-bottom: 4px;
background: var(--bg-secondary);
border-radius: 8px;
cursor: pointer;
font-size: 0.8rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.chat-history-item:hover {
background: var(--email-hover);
}
.chat-history-item.active {
background: var(--user-message);
color: white;
}
.new-chat-btn {
width: 100%;
padding: 6px;
background: var(--user-message);
color: white;
border: none;
border-radius: 20px;
cursor: pointer;
font-size: 0.8rem;
}
.new-chat-btn:hover {
opacity: 0.9;
}
hr {
margin: 10px 0;
border-color: var(--border);
}
</style>
</body>
</html>
โ Back