290 lines
12 KiB
JavaScript
290 lines
12 KiB
JavaScript
// Screen Test - Main JS
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
// --- Element Selectors ---
|
|
const form = document.getElementById('idea-form');
|
|
const submitButton = form.querySelector('button[type="submit"]');
|
|
const personasContainer = document.getElementById('personas-container');
|
|
const personasGrid = document.getElementById('personas-grid');
|
|
const chatContainer = document.getElementById('chat-container');
|
|
const chatCard = document.querySelector('.chat-card');
|
|
const chatPersonaName = document.getElementById('chat-persona-name');
|
|
const chatPersonaIcon = document.getElementById('chat-persona-icon');
|
|
const closeChatBtn = document.getElementById('close-chat');
|
|
const chatLog = document.getElementById('chat-log');
|
|
const chatForm = document.getElementById('chat-form');
|
|
const chatMessageInput = document.getElementById('chat-message-input');
|
|
const sendMessageBtn = document.getElementById('send-message-btn');
|
|
const analysisSection = document.getElementById('analysis-section');
|
|
const generateAnalysisBtn = document.getElementById('generate-analysis-btn');
|
|
const analysisContainer = document.getElementById('analysis-container');
|
|
const analysisContent = document.getElementById('analysis-content');
|
|
|
|
// --- State Variables ---
|
|
let currentSessionId = null;
|
|
let personasData = [];
|
|
let activePersona = null;
|
|
let chatHistory = [];
|
|
|
|
// --- Event Listeners ---
|
|
|
|
// Main form submission -> Generate Personas & Create Session
|
|
if (form) {
|
|
form.addEventListener('submit', function (e) {
|
|
e.preventDefault();
|
|
const audience = document.getElementById('target-audience').value;
|
|
const idea = document.getElementById('business-idea').value;
|
|
|
|
if (!audience || !idea) {
|
|
alert('Please fill out both Target Audience and Business Idea fields.');
|
|
return;
|
|
}
|
|
|
|
// --- Reset UI and Set Loading State ---
|
|
personasContainer.classList.add('d-none');
|
|
chatContainer.classList.add('d-none');
|
|
analysisSection.classList.add('d-none');
|
|
analysisContainer.classList.add('d-none');
|
|
personasGrid.innerHTML = '';
|
|
const originalButtonText = submitButton.innerHTML;
|
|
submitButton.disabled = true;
|
|
submitButton.innerHTML = `<span class="spinner-border spinner-border-sm"></span> Generating...`;
|
|
|
|
// --- Fetch Personas & Create Session ---
|
|
fetch('api/generate_personas.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ audience, idea }),
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) return response.json().then(err => { throw new Error(err.error || 'Unknown error generating personas.') });
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
if (data.session_id && data.personas && data.personas.length > 0) {
|
|
// --- Store Session and Persona Data ---
|
|
currentSessionId = data.session_id;
|
|
personasData = data.personas; // Now contains DB IDs
|
|
|
|
renderPersonas(personasData);
|
|
personasContainer.classList.remove('d-none');
|
|
setTimeout(() => personasContainer.scrollIntoView({ behavior: 'smooth', block: 'start' }), 100);
|
|
} else {
|
|
throw new Error('The AI did not return valid session data. Please try again.');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
alert(`An error occurred: ${error.message}`);
|
|
})
|
|
.finally(() => {
|
|
submitButton.disabled = false;
|
|
submitButton.innerHTML = originalButtonText;
|
|
});
|
|
});
|
|
}
|
|
|
|
// Persona card click -> Open Chat
|
|
personasGrid.addEventListener('click', function(e) {
|
|
const card = e.target.closest('.persona-card');
|
|
if (card) {
|
|
const personaIndex = card.dataset.personaIndex;
|
|
activePersona = personasData[personaIndex]; // activePersona now has the DB ID
|
|
const gradientIndex = card.classList.contains('persona-gradient-1') ? 1 : card.classList.contains('persona-gradient-2') ? 2 : 3;
|
|
openChat(activePersona, gradientIndex);
|
|
}
|
|
});
|
|
|
|
// Close chat button
|
|
closeChatBtn.addEventListener('click', function() {
|
|
chatContainer.classList.add('d-none');
|
|
analysisSection.classList.add('d-none');
|
|
analysisContainer.classList.add('d-none');
|
|
activePersona = null;
|
|
});
|
|
|
|
// Chat form submission -> Send message
|
|
chatForm.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
const message = chatMessageInput.value.trim();
|
|
if (message && activePersona && currentSessionId) {
|
|
addMessageToChatLog(message, 'user');
|
|
chatHistory.push({ sender: 'user', message: message });
|
|
chatMessageInput.value = '';
|
|
chatMessageInput.style.height = 'auto';
|
|
|
|
showTypingIndicator();
|
|
|
|
// --- Fetch Chat Response ---
|
|
fetch('api/chat.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
session_id: currentSessionId,
|
|
message: message,
|
|
persona: activePersona, // persona object now includes the ID
|
|
history: chatHistory.slice(0, -1)
|
|
}),
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) return response.json().then(err => { throw new Error(err.error || 'An API error occurred.') });
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
if (data.response) {
|
|
addMessageToChatLog(data.response, 'persona');
|
|
chatHistory.push({ sender: 'persona', message: data.response });
|
|
} else {
|
|
throw new Error('Empty response from AI.');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Chat Error:', error);
|
|
addMessageToChatLog(`Sorry, I encountered an error: ${error.message}`, 'persona', true);
|
|
})
|
|
.finally(() => {
|
|
hideTypingIndicator();
|
|
});
|
|
}
|
|
});
|
|
|
|
// Analysis button click -> Generate Analysis
|
|
generateAnalysisBtn.addEventListener('click', function() {
|
|
if (!activePersona || !currentSessionId || chatHistory.length < 5) return;
|
|
|
|
const originalButtonText = this.innerHTML;
|
|
this.disabled = true;
|
|
this.innerHTML = `<span class="spinner-border spinner-border-sm"></span> Analyzing...`;
|
|
|
|
// --- Fetch Analysis ---
|
|
fetch('api/analyze_chat.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
session_id: currentSessionId,
|
|
persona: activePersona,
|
|
history: chatHistory
|
|
}),
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) return response.json().then(err => { throw new Error(err.error || 'An API error occurred during analysis.') });
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
if (data.analysis) {
|
|
analysisContent.innerHTML = data.analysis;
|
|
analysisContainer.classList.remove('d-none');
|
|
analysisContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
} else {
|
|
throw new Error('Empty analysis from AI.');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Analysis Error:', error);
|
|
analysisContent.innerHTML = `<div class="alert alert-danger">Sorry, an error occurred during analysis: ${error.message}</div>`;
|
|
analysisContainer.classList.remove('d-none');
|
|
})
|
|
.finally(() => {
|
|
this.disabled = false;
|
|
this.innerHTML = originalButtonText;
|
|
});
|
|
});
|
|
|
|
// Auto-resize textarea for chat input
|
|
chatMessageInput.addEventListener('input', function () {
|
|
this.style.height = 'auto';
|
|
this.style.height = (this.scrollHeight) + 'px';
|
|
});
|
|
|
|
// --- Functions ---
|
|
|
|
function renderPersonas(personas) {
|
|
const personaGradients = ['persona-gradient-1', 'persona-gradient-2', 'persona-gradient-3'];
|
|
personasGrid.innerHTML = personas.map((persona, index) => `
|
|
<div class="col-lg-4 col-md-6">
|
|
<div class="card persona-card h-100 rounded-4 shadow-lg border-0 ${personaGradients[index % 3]}" data-persona-index="${index}" style="cursor: pointer;">
|
|
<div class="card-body p-4">
|
|
<h3 class="card-title fw-bold">${persona.name}</h3>
|
|
<p class="card-subtitle mb-2 text-white-75">${persona.age}, ${persona.occupation}</p>
|
|
<div class="mt-4">
|
|
<h6 class="fw-semibold">Traits:</h6><p>${persona.traits}</p>
|
|
<h6 class="fw-semibold">Concerns:</h6><p>${persona.concerns}</p>
|
|
<h6 class="fw-semibold">Style:</h6><p>${persona.style}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`).join('');
|
|
}
|
|
|
|
function openChat(persona, gradientIndex) {
|
|
chatPersonaName.textContent = persona.name;
|
|
const cardGradientClass = `persona-gradient-${gradientIndex}`;
|
|
chatCard.querySelector('.card-header').className = `card-header d-flex justify-content-between align-items-center p-3 rounded-top-5 ${cardGradientClass}`;
|
|
chatPersonaIcon.className = "bi bi-person-circle fs-3 me-3";
|
|
|
|
chatLog.innerHTML = '';
|
|
const welcomeMessage = `Hello! I'm ${persona.name}. Ask me anything about the business idea.`;
|
|
addMessageToChatLog(welcomeMessage, 'persona');
|
|
chatHistory = [{ sender: 'persona', message: welcomeMessage }];
|
|
|
|
chatContainer.classList.remove('d-none');
|
|
analysisSection.classList.add('d-none');
|
|
analysisContainer.classList.add('d-none');
|
|
generateAnalysisBtn.disabled = true;
|
|
|
|
chatContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
}
|
|
|
|
function addMessageToChatLog(message, sender, isError = false) {
|
|
const messageElement = document.createElement('div');
|
|
messageElement.className = `chat-message ${sender === 'user' ? 'user' : 'persona'}`;
|
|
|
|
const bubble = document.createElement('div');
|
|
bubble.className = 'message-bubble';
|
|
if (isError) bubble.classList.add('bg-danger', 'text-white');
|
|
bubble.textContent = message;
|
|
|
|
const time = document.createElement('div');
|
|
time.className = 'message-time';
|
|
time.textContent = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
|
|
messageElement.appendChild(bubble);
|
|
messageElement.appendChild(time);
|
|
chatLog.appendChild(messageElement);
|
|
chatLog.scrollTop = chatLog.scrollHeight;
|
|
|
|
// Check to enable analysis button (user messages count towards total)
|
|
if (sender === 'user' && chatHistory.filter(m => m.sender === 'user').length >= 2) {
|
|
analysisSection.classList.remove('d-none');
|
|
generateAnalysisBtn.disabled = false;
|
|
}
|
|
}
|
|
|
|
function showTypingIndicator() {
|
|
sendMessageBtn.disabled = true;
|
|
let indicator = chatLog.querySelector('.typing-indicator');
|
|
if (!indicator) {
|
|
indicator = document.createElement('div');
|
|
indicator.className = 'chat-message persona typing-indicator';
|
|
indicator.innerHTML = `
|
|
<div class="message-bubble">
|
|
<div class="spinner-grow spinner-grow-sm" role="status"></div>
|
|
<div class="spinner-grow spinner-grow-sm mx-1" role="status"></div>
|
|
<div class="spinner-grow spinner-grow-sm" role="status"></div>
|
|
</div>
|
|
`;
|
|
chatLog.appendChild(indicator);
|
|
}
|
|
chatLog.scrollTop = chatLog.scrollHeight;
|
|
}
|
|
|
|
function hideTypingIndicator() {
|
|
sendMessageBtn.disabled = false;
|
|
const indicator = chatLog.querySelector('.typing-indicator');
|
|
if (indicator) {
|
|
indicator.remove();
|
|
}
|
|
}
|
|
});
|