IX AI 2 - Ideasicle X
Approved Ideas: 0

Super Prompt Generation

Step 1: Select Hallucination Level

Choose how creative or conventional you want the AI's ideas to be.

Hallucination Level

Step 2: Choose AI Engine

Select the AI engine you want to use for generating ideas.

AI Engine

Step 3: Idea Type

Enter the type of idea you want the AI to generate (e.g., ad campaigns, TV spots, product names).

Idea Type

Step 4: Generate Prompt

Type It In: directly in the white space to the right

Brief Builder: fill out a short form to give the brief structure

Upload Brief: upload PDF of existing creative brief

Once the brief is visible in the white space, click “Generate Prompt” and it will be merged with the levels of hallucination and idea type you selected.

NOTE: be specific about additional details to ensure the AI understands your needs.

Creative Brief
// let sessionIdeas = []; let lastIdeas = []; let lastHallucinationLevel = 'none'; let lastAiEngine = 'Grok'; let lastBrief = ''; let lastIdeaType = ''; let lastGeneralFeedback = ''; let stage2Active = false; let suppressWarning = false; let aiEngineWindow = null; // Global DOM elements let stage1, stage2, notification, generatePromptBtn, clearInputBtn, processBtn, generateFeedbackBtn, miniCardsContainer, generatePdfBtn, noIdeas, modal, modalContent, modalClose, modalApproveCheckbox, modalIdeaNotes, approvedCount, backToInput, navInstructions, navTips, navSuggestionBox, instructionsModal, tipsModal, suggestionBoxModal, aiEngineModal, openAiEngineBtn, aiEngineName, feedbackPromptModal, closeFeedbackPromptModal, feedbackAiEngineName, briefBuilderBtn, uploadBriefBtn, uploadBriefInput, briefBuilderModal, saveBriefBuilder, cancelBriefBuilder, briefBuilderLink, uploadBriefLink, ideaTypeInput, submitIdeaTypeBtn, briefInput; function initializeDOMElements() { console.log('Initializing DOM elements at:', new Date().toLocaleString()); const elements = { stage1: 'stage1', stage2: 'stage2', notification: 'notification', generatePromptBtn: 'generatePromptBtn', clearInputBtn: 'clearInputBtn', processBtn: 'processBtn', generateFeedbackBtn: 'generateFeedbackBtn', miniCardsContainer: 'miniCardsContainer', generatePdfBtn: 'generatePdfBtn', noIdeas: 'noIdeas', modal: 'ideaModal', modalContent: 'modalIdeaContent', modalClose: 'modalClose', modalApproveCheckbox: 'modalApproveCheckbox', modalIdeaNotes: 'modalIdeaNotes', approvedCount: 'approvedCount', backToInput: 'backToInput', navInstructions: 'navInstructions', navTips: 'navTips', navSuggestionBox: 'navSuggestionBox', instructionsModal: 'instructionsModal', tipsModal: 'tipsModal', suggestionBoxModal: 'suggestionBoxModal', aiEngineModal: 'aiEngineModal', openAiEngineBtn: 'openAiEngineBtn', aiEngineName: 'aiEngineName', feedbackPromptModal: 'feedbackPromptModal', closeFeedbackPromptModal: 'closeFeedbackPromptModal', feedbackAiEngineName: 'feedbackAiEngineName', briefBuilderBtn: 'briefBuilderBtn', uploadBriefBtn: 'uploadBriefBtn', uploadBriefInput: 'uploadBriefInput', briefBuilderModal: 'briefBuilderModal', saveBriefBuilder: 'saveBriefBuilder', cancelBriefBuilder: 'cancelBriefBuilder', briefBuilderLink: 'briefBuilderLink', uploadBriefLink: 'uploadBriefLink', ideaTypeInput: 'ideaTypeInput', submitIdeaTypeBtn: 'submitIdeaTypeBtn', briefInput: 'briefInput' }; for (const [key, id] of Object.entries(elements)) { window[key] = document.getElementById(id); if (!window[key]) { console.warn(`${key} (ID: ${id}) not found in DOM`); } else { console.log(`${key} found in DOM`); } } return Object.values(elements).every(id => document.getElementById(id)); } // function showNotification(message, type, duration = 3000) { console.log(`Showing notification: ${message}, Type: ${type}, Duration: ${duration}`); if (notification) { notification.textContent = message; notification.className = `notification ${type}`; notification.style.display = 'block'; setTimeout(() => { if (notification) notification.style.display = 'none'; console.log(`Hiding notification: ${message}`); }, duration); } else { console.error('Notification element not found, using alert'); alert(message); } } // function clearInfoBoxes(containerId) { const container = document.getElementById(containerId); if (container) { const infoBoxes = container.getElementsByClassName('info-box'); while (infoBoxes.length > 0) { infoBoxes[0].remove(); console.log(`Removed info-box in ${containerId}`); } } } // function resetApp(clearBrief = false) { console.log('Resetting app, clearBrief:', clearBrief); sessionIdeas = []; lastIdeas = []; lastGeneralFeedback = ''; stage2Active = false; aiEngineWindow = null; if (clearBrief) { if (briefInput) briefInput.value = ''; if (ideaTypeInput) { ideaTypeInput.value = ''; ideaTypeInput.disabled = false; } lastBrief = ''; lastIdeaType = ''; lastHallucinationLevel = 'none'; lastAiEngine = 'Grok'; const noneRadio = document.querySelector('input[name="hallucinationLevel"][value="none"]'); const grokRadio = document.querySelector('input[name="aiEngine"][value="Grok"]'); if (noneRadio) noneRadio.checked = true; if (grokRadio) grokRadio.checked = true; if (briefInput) briefInput.disabled = true; if (briefBuilderBtn) briefBuilderBtn.disabled = true; if (uploadBriefBtn) uploadBriefBtn.disabled = true; if (generatePromptBtn) generatePromptBtn.disabled = true; if (clearInputBtn) clearInputBtn.disabled = true; if (submitIdeaTypeBtn && ideaTypeInput) { submitIdeaTypeBtn.disabled = !ideaTypeInput.value.trim(); submitIdeaTypeBtn.title = ideaTypeInput.value.trim() ? 'Submit idea type' : 'Enter an idea type to submit'; const inputEvent = new Event('input', { bubbles: true }); ideaTypeInput.dispatchEvent(inputEvent); } } const llmResponse = document.getElementById('llmResponse'); if (llmResponse) llmResponse.value = ''; const ideasContainer = document.getElementById('ideasContainer'); if (ideasContainer) ideasContainer.innerHTML = ''; const stage2Actions = document.getElementById('stage2Actions'); if (stage2Actions) stage2Actions.style.display = 'none'; const approvedIdeas = document.getElementById('approvedIdeas'); if (approvedIdeas) approvedIdeas.style.display = 'none'; if (stage2) stage2.style.display = 'none'; if (generatePromptBtn) { generatePromptBtn.disabled = true; generatePromptBtn.title = 'Submit an idea type and brief to generate a prompt'; } ['stage1', 'stage2'].forEach(clearInfoBoxes); updateMiniCards(); updateApprovedCount(); if (backToInput) backToInput.style.display = 'none'; } // function updateApprovedCount() { if (approvedCount) { approvedCount.textContent = sessionIdeas.length; console.log('Approved count updated:', sessionIdeas.length); } } // function generatePDF() { try { console.log('Generating PDF, sessionIdeas count:', sessionIdeas.length); if (!sessionIdeas.length) { showNotification('No ideas to generate PDF', 'error', 5000); return; } const { jsPDF } = window.jspdf || {}; if (!jsPDF) { console.error('jsPDF library not loaded'); showNotification('PDF generation failed: jsPDF not loaded', 'error', 5000); return; } const doc = new jsPDF(); doc.setFont('helvetica', 'bold'); doc.setFontSize(16); doc.text('IX AI Approved Ideas', 20, 20); doc.setFont('helvetica', 'normal'); doc.setFontSize(12); let y = 30; sessionIdeas.forEach((idea, index) => { console.log('Adding idea to PDF:', idea.title, 'y:', y); if (y > 270) { doc.addPage(); y = 20; } doc.setFont('helvetica', 'normal'); doc.text(`Idea #${idea.ideaNumber}${idea.reaction ? ' (Revised)' : ''}`, 20, y); y += 8; doc.setFont('helvetica', 'bold'); doc.setFontSize(14); doc.text(idea.title || 'Untitled', 20, y, { maxWidth: 170 }); y += 8; doc.setFont('helvetica', 'normal'); doc.setFontSize(12); const descLines = doc.splitTextToSize(idea.description || 'No description', 170); doc.text(descLines, 20, y); y += descLines.length * 6 + 0.5; if (idea.rationale && idea.rationale.trim()) { doc.setFont('helvetica', 'bold'); doc.text('Rationale:', 20, y); doc.setFont('helvetica', 'normal'); const rationaleLines = doc.splitTextToSize(idea.rationale.replace(/[^ -~]/g, ''), 170); doc.text(rationaleLines, 20, y + 4, { maxWidth: 170 }); y += rationaleLines.length * 6 + 6; } if (idea.notes && idea.notes.trim()) { doc.setFont('helvetica', 'bold'); doc.text('Notes:', 20, y); doc.setFont('helvetica', 'normal'); const notesLines = doc.splitTextToSize(idea.notes.replace(/[^ -~]/g, ''), 170); doc.text(notesLines, 20, y + 4, { maxWidth: 170 }); y += notesLines.length * 6 + 6; } }); doc.save('IX_AI_Approved_Ideas.pdf'); showNotification('PDF Generated', 'success', 3000); } catch (e) { showNotification('Error generating PDF: ' + e.message, 'error', 5000); console.error('PDF generation error:', e); } } // function saveBriefBuilderInput() { const promoting = document.getElementById('briefPromoting')?.value.trim() || ''; const audience = document.getElementById('briefAudience')?.value.trim() || ''; const message = document.getElementById('briefMessage')?.value.trim() || ''; const extra = document.getElementById('briefExtra')?.value.trim() || ''; console.log('Saving Brief Builder input:', { promoting, audience, message, extra }); if (briefInput) { const ideaType = lastIdeaType || 'unspecified'; briefInput.value = [ `Idea Type: ${ideaType}`, `What are we promoting?: ${promoting}`, `Who is the target audience?: ${audience}`, `What is the key message?: ${message}`, `What else should the AI know?: ${extra}` ].filter(line => !line.endsWith(':')).join('\n'); briefInput.disabled = false; console.log('Brief Builder saved to textarea:', briefInput.value); if (briefBuilderModal) { briefBuilderModal.style.display = 'none'; document.body.classList.remove('modal-open'); } const inputEvent = new Event('input', { bubbles: true }); briefInput.dispatchEvent(inputEvent); resetPromptState(); briefInput.scrollIntoView({ behavior: 'smooth', block: 'center' }); return true; } else { console.error('briefInput element not found'); showNotification('Error saving brief', 'error', 5000); return false; } } // async function handlePdfUpload(file) { console.log('Handling PDF upload:', file?.name); if (!file || file.type !== 'application/pdf') { showNotification('Please upload a valid PDF file.', 'error', 5000); return; } try { if (!window.pdfjsLib) { console.error('pdf.js library not loaded'); showNotification('PDF processing failed: pdf.js not loaded', 'error', 5000); return; } const arrayBuffer = await file.arrayBuffer(); const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise; let text = ''; for (let i = 1; i <= pdf.numPages; i++) { const page = await pdf.getPage(i); const content = await page.getTextContent(); const pageText = content.items.map(item => item.str.trim()).filter(str => str).join('\n'); text += (text ? '\n\n' : '') + pageText; } console.log('Extracted PDF text length:', text.length); if (briefInput) { const cleanedText = text.replace(/\n\s*\n+/g, '\n').replace(/\s+/g, ' ').trim(); briefInput.value = cleanedText ? `Idea Type: ${lastIdeaType || 'unspecified'}\nUploaded Brief:\n${cleanedText}` : 'No readable text found in PDF.\n'; briefInput.disabled = false; console.log('PDF text pasted to textarea:', briefInput.value.substring(0, 100) + '...'); showNotification('PDF brief uploaded successfully. Please review and edit the text below.', 'success', 5000); const inputEvent = new Event('input', { bubbles: true }); briefInput.dispatchEvent(inputEvent); resetPromptState(); briefInput.scrollIntoView({ behavior: 'smooth', block: 'center' }); } else { console.error('briefInput element not found'); showNotification('Error pasting PDF text', 'error', 5000); } } catch (e) { console.error('PDF processing error:', e); showNotification('Failed to read PDF. It may be scanned or corrupted. Try a text-based PDF or manual input.', 'error', 5000); } } // function generatePrompt(brief, ideaType) { console.log('Generating prompt with ideaType:', ideaType); if (!brief) throw new Error('No brief provided'); if (!ideaType) throw new Error('No idea type provided'); const hallucinationLevel = document.querySelector('input[name="hallucinationLevel"]:checked')?.value; const aiEngine = document.querySelector('input[name="aiEngine"]:checked')?.value; if (!hallucinationLevel) throw new Error('No hallucination level selected'); if (!aiEngine) throw new Error('No AI engine selected'); console.log('Selected hallucination level:', hallucinationLevel, 'AI engine:', aiEngine); const ideaTypeKeywords = [ 'tv campaign', 'tv spot', 'television ad', 'television spot', 'radio campaign', 'radio spot', 'radio ad', 'print ad', 'print campaign', 'magazine ad', 'billboard', 'outdoor ad', 'outdoor campaign', 'social media', 'social media campaign', 'social post', 'video', 'video ad', 'video campaign', 'pr stunt', 'publicity stunt', 'public relations', 'product name', 'company name', 'feature name', 'naming', 'blog post', 'blog', 'article', 'content', 'coasters', 'bar coasters', 'coaster designs', 'advertising campaign', 'ad campaign' ]; const ideaTypeLower = ideaType.toLowerCase(); let detectedIdeaType = ideaTypeKeywords.find(keyword => ideaTypeLower.includes(keyword)) || ideaTypeLower; console.log('Detected idea type:', detectedIdeaType); let prompt = ''; let hallucinationInstruction = ''; let outputInstructions = ''; const baseOutputInstructions = ` Output instructions: You MUST generate EXACTLY FIVE ideas. Each idea MUST be formatted as a single block with the fields "Title:", "Description:", and "Rationale:", separated by single newlines. The description MUST be a MAXIMUM of 3 sentences, where a sentence ends with a period, exclamation point, or question mark (can be fewer but not more). The rationale MUST be EXACTLY 1 sentence, with no citations or references (e.g., [1], [2]). Use the exact labels "Title:", "Description:", and "Rationale:" with colons, ensuring each label is bolded in the output (e.g., **Title:**). Do not use headers, numbers, bullet points, or any other separators between ideas. Separate each idea block with exactly two blank lines (double newlines). Do not include any introductions, conclusions, extra text, or formatting deviations. Each of the five ideas MUST represent a radically different approach to the task, with no overlap in themes or execution, and must avoid repeating concepts or themes from any previously provided ideas in this session. Any deviation from this format, including incorrect sentence counts, non-bolded labels, or fewer/more than five ideas, will break the system, so follow it precisely. `; if (detectedIdeaType.includes('name') || detectedIdeaType.includes('naming')) { outputInstructions = ` ${baseOutputInstructions} Each idea MUST be a naming concept (e.g., product name, company name, feature name) as specified in the brief. The description MUST start with "This name..." and explain the name’s concept and appeal in 1-3 sentences. Format for each idea: **Title:** [Name] **Description:** [Maximum 3 sentences starting with "This name..."] **Rationale:** [Exactly 1 sentence explaining why the name is effective] `; } else { outputInstructions = ` ${baseOutputInstructions} Each idea MUST be a ${detectedIdeaType} concept, with the first sentence of the description explicitly stating it is a ${detectedIdeaType} and summarizing its main focus. The description should outline the ${detectedIdeaType}’s key elements or execution, tailored to the audience specified in the brief. All ideas MUST strictly adhere to the ${detectedIdeaType} format and not use any other medium or format. Format for each idea: **Title:** [${detectedIdeaType} Title] **Description:** [Maximum 3 sentences starting with "This ${detectedIdeaType}..."] **Rationale:** [Exactly 1 sentence explaining why the ${detectedIdeaType} is effective] `; } switch (hallucinationLevel) { case 'none': hallucinationInstruction = `Do not apply any hallucination; generate ${detectedIdeaType} ideas strictly based on the brief and conventional ${detectedIdeaType.includes('name') ? 'naming' : detectedIdeaType.includes('blog') ? 'content marketing' : detectedIdeaType.includes('coaster') ? 'promotional' : 'advertising'} principles, mimicking a temperature of 0.1 for maximum predictability.`; prompt = ` Creative brief: ${brief} Instructions: ${hallucinationInstruction} Generate EXACTLY FIVE ${detectedIdeaType} ideas based on the provided creative brief, adhering strictly to the format specified below. Act as an expert on the target audience described in the creative brief, ensuring all ideas are highly relevant to their preferences, behaviors, and values. ${outputInstructions} `; console.log(`Generated prompt for "none" hallucination level (${detectedIdeaType})`); break; case 'microdose': hallucinationInstruction = `Introduce a single, subtle hallucination per ${detectedIdeaType} idea (e.g., an unexpected but plausible angle or perspective), mimicking a temperature of 0.3 for slight randomness, while keeping ideas highly feasible.`; prompt = ` You are a strategic ${detectedIdeaType.includes('name') ? 'naming' : detectedIdeaType.includes('blog') ? 'content marketing' : detectedIdeaType.includes('coaster') ? 'promotional' : 'advertising'} expert tasked with creating practical, audience-focused ${detectedIdeaType} ideas based on the provided creative brief. Your goal is to develop ideas that enhance conventional ${detectedIdeaType} formats with subtle, innovative twists, ensuring high feasibility and alignment with the audience’s values and behaviors. Creative brief: ${brief} Instructions for Creative Output: - ${hallucinationInstruction} - Act as an expert on the target audience described in the creative brief, ensuring all ideas are highly relevant to their preferences, behaviors, and values. - Maximize diversity across the five ideas by exploring distinct themes (e.g., humor, inspiration, mystery), emotional tones (e.g., joy, curiosity, awe), and execution styles, ensuring no conceptual overlap. - For each idea, adopt a unique creative lens inspired by a distinct era, culture, genre, or imagined world to ensure varied perspectives. - Focus on established ${detectedIdeaType} formats with one subtle, innovative twist per idea, grounded in current cultural trends and proven strategies. - Avoid predictable ${detectedIdeaType.includes('name') ? 'naming conventions' : detectedIdeaType.includes('blog') ? 'blog content tropes' : detectedIdeaType.includes('coaster') ? 'promotional tropes' : 'advertising tropes'}, ensuring ideas are fresh yet executable. - All ideas MUST be ${detectedIdeaType} concepts, regardless of any other types mentioned in the brief. ${outputInstructions} `; console.log(`Generated prompt for "microdose" hallucination level (${detectedIdeaType})`); break; case 'buzzed': hallucinationInstruction = `Fuse two seemingly unrelated concepts to create bold, surprising ${detectedIdeaType} ideas, mimicking a temperature of 0.7 for moderate randomness and creativity.`; prompt = ` You are a bold creative director tasked with pushing ${detectedIdeaType.includes('name') ? 'naming' : detectedIdeaType.includes('blog') ? 'content marketing' : detectedIdeaType.includes('coaster') ? 'promotional' : 'advertising'} boundaries while keeping ideas feasible and impactful, based on the provided creative brief. Your goal is to generate innovative ${detectedIdeaType} ideas that combine unexpected concepts into surprising, executable concepts, drawing inspiration from any domain of human knowledge or imagination to captivate the audience. Creative brief: ${brief} Instructions for Creative Output: - ${hallucinationInstruction} - Act as an expert on the target audience described in the creative brief, ensuring all ideas are highly relevant to their preferences, behaviors, and values. - Maximize diversity across the five ideas by exploring distinct themes (e.g., humor, inspiration, mystery), emotional tones (e.g., joy, curiosity, awe), and execution styles, ensuring no conceptual overlap. - For each idea, adopt a unique creative lens inspired by a distinct era, culture, genre, or imagined world to ensure varied perspectives. - Ensure ideas push creative boundaries but remain anchored to the brand’s essence and audience expectations, with clear execution paths. - Avoid predictable ${detectedIdeaType.includes('name') ? 'naming conventions' : detectedIdeaType.includes('blog') ? 'blog content tropes' : detectedIdeaType.includes('coaster') ? 'promotional tropes' : 'advertising tropes'}, focusing on surprising yet implementable concepts. - All ideas MUST be ${detectedIdeaType} concepts, regardless of any other types mentioned in the brief. ${outputInstructions} `; console.log(`Generated prompt for "buzzed" hallucination level (${detectedIdeaType})`); break; case 'tripping': hallucinationInstruction = `Generate surreal, boundary-defying ${detectedIdeaType} ideas with maximal creative freedom, mimicking a temperature of 1.2 for high randomness and hallucination.`; prompt = ` You are a visionary artist unbound by reality, tasked with redefining ${detectedIdeaType.includes('name') ? 'naming' : detectedIdeaType.includes('blog') ? 'content marketing' : detectedIdeaType.includes('coaster') ? 'promotional' : 'advertising'} itself based on the provided creative brief. Your goal is to create surreal, transcendent ${detectedIdeaType} ideas that invent new formats, emotions, or experiences, drawing inspiration from any domain of human knowledge or imagination. Creative brief: ${brief} Instructions for Creative Output: - ${hallucinationInstruction} - Act as an expert on the target audience described in the creative brief, ensuring all ideas are highly relevant to their preferences, behaviors, and values, even if expressed in unconventional ways. - Maximize diversity across the five ideas by exploring distinct themes (e.g., humor, inspiration, mystery), emotional tones (e.g., joy, curiosity, awe), and execution styles, ensuring no conceptual overlap. - For each idea, adopt a unique creative lens inspired by a distinct era, culture, genre, or imagined world to ensure varied perspectives. - Invent entirely new ${detectedIdeaType} formats or experiences that challenge conventional ${detectedIdeaType.includes('blog') ? 'content' : detectedIdeaType.includes('coaster') ? 'promotional items' : 'media'}, prioritizing imagination and unexpected emotional impact. - Avoid predictable ${detectedIdeaType.includes('name') ? 'naming conventions' : detectedIdeaType.includes('blog') ? 'blog content tropes' : detectedIdeaType.includes('coaster') ? 'promotional tropes' : 'advertising tropes'}, focusing on visionary concepts that may be speculative or futuristic. - All ideas MUST be ${detectedIdeaType} concepts, regardless of any other types mentioned in the brief. ${outputInstructions} `; console.log(`Generated prompt for "tripping" hallucination level (${detectedIdeaType})`); break; default: throw new Error('Invalid hallucination level selected'); } return prompt; } // function showAiEngineModal(aiEngine, fullPrompt, isFeedback = false) { console.log('Showing AI engine modal for:', aiEngine, 'isFeedback:', isFeedback); if (!aiEngineName || !openAiEngineBtn || !aiEngineModal) { console.error('AI engine modal elements missing:', { aiEngineName, openAiEngineBtn, aiEngineModal }); showNotification('Error: AI engine modal elements missing', 'error', 5000); return; } const aiEngineUrls = { 'Grok': 'https://x.com/i/grok', 'ChatGPT': 'https://chat.openai.com', 'Perplexity': 'https://www.perplexity.ai' }; const url = aiEngineUrls[aiEngine] || 'https://x.com/i/grok'; aiEngineName.textContent = aiEngine; openAiEngineBtn.textContent = isFeedback ? 'Go to Existing AI Tab' : 'Open AI Engine'; openAiEngineBtn.setAttribute('aria-label', isFeedback ? 'Go to existing AI engine tab' : 'Open selected AI engine'); openAiEngineBtn.onclick = () => { console.log(isFeedback ? 'Focusing existing AI engine tab:' : 'Opening AI engine tab:', url); if (aiEngineWindow && !aiEngineWindow.closed) { aiEngineWindow.focus(); } else { aiEngineWindow = window.open(url, 'aiEngineTab'); } aiEngineModal.style.display = 'none'; document.body.classList.remove('modal-open'); navigator.clipboard.writeText(fullPrompt).then(() => { showNotification(`Prompt copied. Paste it into the same ${aiEngine} thread and return with the response.`, 'success', 5000); if (stage2) stage2.style.display = 'block'; const llmResponse = document.getElementById('llmResponse'); if (llmResponse) { llmResponse.scrollIntoView({ behavior: 'smooth', block: 'center' }); } else if (stage2) { console.error('llmResponse textarea not found for scrolling'); window.scrollTo({ top: stage2.offsetTop, behavior: 'smooth' }); } }).catch(err => { showNotification('Clipboard access failed.', 'error', 5000); console.error('Clipboard write error:', err); }); }; aiEngineModal.style.display = 'block'; document.body.classList.add('modal-open'); } // function parseLLMResponse(text) { console.log('Parsing LLM response, raw text length:', text.length); const ideas = { newIdeas: [], revisedIdeas: [], generalFeedbackReaction: '' }; const normalizedText = text.replace(/\r\n|\r/g, '\n').trim(); console.log('Normalized text length:', normalizedText.length); const blocks = normalizedText.split(/\n{1,2}/).map(block => block.trim()).filter(block => block); console.log('Parsed blocks count:', blocks.length); let newIdeaNumber = 1; let parsingErrors = []; for (let block of blocks) { if (block.match(/^General\s*Feedback\s*Reaction\s*:/i)) { ideas.generalFeedbackReaction = block.replace(/^General\s*Feedback\s*Reaction\s*:\s*/i, '').trim(); console.log('Parsed general feedback reaction:', ideas.generalFeedbackReaction); continue; } const lines = block.split('\n').map(line => line.trim()).filter(line => line); let idea = { ideaNumber: '', title: '', description: '', rationale: '', reaction: '' }; let currentField = null; let tempFields = { title: [], description: [], rationale: [], reaction: [] }; for (let i = 0; i < lines.length; i++) { let cleanLine = lines[i].replace(/^\*\*|\*\*$/g, '').replace(/\*/g, '').trim(); if (cleanLine.match(/^Title\s*:/i)) { currentField = 'title'; tempFields.title.push(cleanLine.replace(/^Title\s*:/i, '').trim()); } else if (cleanLine.match(/^Description\s*:/i)) { currentField = 'description'; tempFields.description.push(cleanLine.replace(/^Description\s*:/i, '').trim()); for (let j = i + 1; j < lines.length; j++) { let nextLine = lines[j].replace(/^\*\*|\*\*$/g, '').replace(/\*/g, '').trim(); if (nextLine.match(/^Rationale\s*:/i) || nextLine.match(/^Reaction\s*to\s*feedback\s*:/i) || nextLine.match(/^Title\s*:/i)) { break; } tempFields.description.push(nextLine); i = j; } } else if (cleanLine.match(/^Rationale\s*:/i)) { currentField = 'rationale'; tempFields.rationale.push(cleanLine.replace(/^Rationale\s*:/i, '').trim()); } else if (cleanLine.match(/^Reaction\s*to\s*feedback\s*:/i)) { currentField = 'reaction'; tempFields.reaction.push(cleanLine.replace(/^Reaction\s*to\s*feedback\s*:/i, '').trim()); } else if (currentField) { tempFields[currentField].push(cleanLine); } else { tempFields.description.push(cleanLine); } } idea.title = tempFields.title.join(' ').trim(); idea.description = tempFields.description.filter(line => line).join(' ').trim(); idea.rationale = tempFields.rationale.join(' ').trim().replace(/\[\d+\](?:\[\d+\])*/g, ''); idea.reaction = tempFields.reaction.join(' ').trim(); if (idea.title || idea.description) { if (!idea.title) idea.title = 'Untitled'; if (!idea.description) idea.description = 'No description provided.'; if (!idea.rationale && !idea.reaction) { idea.rationale = 'No rationale provided.'; console.warn('No rationale found for idea:', idea.title); } if (idea.description) { let sentences = idea.description.match(/(? s.trim()).map(s => s.replace(/[.!?]$/, '').trim()) : [idea.description.trim()]; sentences = sentences.filter(s => s && !/[.!?]/.test(s)); if (sentences.length > 3) { idea.description = sentences.slice(0, 3).join('. ') + (sentences[2].endsWith('.') ? '' : '.'); console.log('Limited description to 3 sentences for idea:', idea.title); } else { idea.description = idea.description.trim(); if (!/[.!?]$/.test(idea.description) && sentences.length > 0) { idea.description += '.'; } } } idea.ideaNumber = newIdeaNumber.toString(); if (idea.reaction) { ideas.revisedIdeas.push(idea); } else { ideas.newIdeas.push(idea); } newIdeaNumber++; console.log('Valid idea added:', idea); } else { parsingErrors.push(`Skipped invalid block (missing title and description): ${block.substring(0, 100)}...`); console.warn('Skipped invalid block:', block); } } if (parsingErrors.length) { console.error('Parsing errors encountered:', parsingErrors); } if (ideas.newIdeas.length > 5) { console.warn(`Received ${ideas.newIdeas.length} new ideas, limiting to 5`); ideas.newIdeas = ideas.newIdeas.slice(0, 5); showNotification('Received more than 5 new ideas. Displaying only the first 5.', 'error', 5000); } if (!ideas.newIdeas.length && !ideas.revisedIdeas.length && !ideas.generalFeedbackReaction) { console.error('No valid ideas or feedback reaction parsed. Raw response:', text.substring(0, 500)); showNotification('No valid ideas or feedback found. Ensure the AI response includes ideas with a Title, Description, or General Feedback Reaction.', 'error', 5000); } else if (ideas.newIdeas.length < 5 && !ideas.revisedIdeas.length && ideas.newIdeas.length > 0) { console.warn(`Only ${ideas.newIdeas.length} new ideas parsed. Expected 5.`); showNotification(`Only ${ideas.newIdeas.length} ideas received. Check AI response formatting for Title, Description, and Rationale fields.', 'error', 5000); } console.log('Final parsed ideas:', ideas); return ideas; } // function renderIdeas(ideas) { console.log('Rendering ideas to screen, count:', ideas.newIdeas.length + ideas.revisedIdeas.length); const ideasContainer = document.getElementById('ideasContainer'); if (!ideasContainer) { console.error('Ideas container not found'); showNotification('Error: Ideas container missing', 'error', 5000); return; } ideasContainer.innerHTML = ''; if (!ideas.newIdeas.length && !ideas.revisedIdeas.length && !ideas.generalFeedbackReaction && !lastGeneralFeedback) { ideasContainer.innerHTML = '

No ideas or feedback found. Please check the AI response format.

'; showNotification('No ideas or feedback found in response', 'error', 5000); console.warn('No ideas, general feedback reaction, or user feedback to render'); return; } if (lastGeneralFeedback) { const userFeedbackDiv = document.createElement('div'); userFeedbackDiv.className = 'general-feedback-card'; userFeedbackDiv.innerHTML = `

Your General Feedback

${lastGeneralFeedback}

`; ideasContainer.appendChild(userFeedbackDiv); } if (ideas.generalFeedbackReaction) { const generalFeedbackDiv = document.createElement('div'); generalFeedbackDiv.className = 'general-feedback-reaction'; generalFeedbackDiv.innerHTML = `

Reaction to General Feedback

${ideas.generalFeedbackReaction}

`; ideasContainer.appendChild(generalFeedbackDiv); } let revisedIdeaCounter = 1; ideas.revisedIdeas.forEach((idea, index) => { console.log(`Rendering revised idea:`, idea.title, 'Index:', index); const card = document.createElement('div'); card.className = 'idea-card revised'; card.dataset.ideaNumber = revisedIdeaCounter.toString(); card.innerHTML = `

Idea #${revisedIdeaCounter} (Revised)

Title: ${idea.title || 'Untitled'}

Reaction to feedback: ${idea.reaction || 'No reaction provided'}

Description: ${idea.description || 'No description'}

${idea.rationale && idea.rationale.trim() ? `

Rationale: ${idea.rationale.trim()}

` : ''}
`; const approveCheckbox = card.querySelector(`#approve-${index}`); if (approveCheckbox) { approveCheckbox.addEventListener('change', () => { const paragraphs = Array.from(card.querySelectorAll('p')); const titleP = paragraphs.find(p => p.textContent.startsWith('Title:')); const descP = paragraphs.find(p => p.textContent.match(/^Description:/)); const reactionP = paragraphs.find(p => p.textContent.startsWith('Reaction to feedback:')); const rationaleP = paragraphs.find(p => p.textContent.startsWith('Rationale:')); const ideaData = { ideaNumber: revisedIdeaCounter.toString(), title: titleP ? titleP.textContent.replace(/^Title:/, '').trim() : 'Untitled', description: descP ? descP.textContent.replace(/^Description:/, '').trim() : 'No description', rationale: rationaleP ? rationaleP.textContent.replace(/^Rationale:/, '').trim() : '', reaction: reactionP ? reactionP.textContent.replace(/^Reaction to feedback:/, '').trim() : '', notes: idea.notes || '' }; console.log('Approval change for idea:', ideaData, 'Checked:', approveCheckbox.checked); if (approveCheckbox.checked) { saveAndDisplayMiniCards([ideaData]); } else { sessionIdeas = sessionIdeas.filter(stored => stored.title !== ideaData.title || stored.description !== ideaData.description || stored.reaction !== ideaData.reaction); updateMiniCards(); } }); } ideasContainer.appendChild(card); revisedIdeaCounter++; }); let newIdeaCounter = 1; ideas.newIdeas.forEach((idea, index) => { console.log(`Rendering new idea:`, idea.title, 'Index:', index); const card = document.createElement('div'); card.className = 'idea-card'; card.dataset.ideaNumber = newIdeaCounter.toString(); card.innerHTML = `

Idea #${newIdeaCounter}

Title: ${idea.title || 'Untitled'}

Description: ${idea.description || 'No description'}

${idea.rationale && idea.rationale.trim() ? `

Rationale: ${idea.rationale.trim()}

` : ''}
`; const approveCheckbox = card.querySelector(`#approve-${index + ideas.revisedIdeas.length}`); if (approveCheckbox) { approveCheckbox.addEventListener('change', () => { const paragraphs = Array.from(card.querySelectorAll('p')); const titleP = paragraphs.find(p => p.textContent.startsWith('Title:')); const descP = paragraphs.find(p => p.textContent.match(/^Description:/)); const rationaleP = paragraphs.find(p => p.textContent.startsWith('Rationale:')); const ideaData = { ideaNumber: newIdeaCounter.toString(), title: titleP ? titleP.textContent.replace(/^Title:/, '').trim() : 'Untitled', description: descP ? descP.textContent.replace(/^Description:/, '').trim() : 'No description', rationale: rationaleP ? rationaleP.textContent.replace(/^Rationale:/, '').trim() : '', reaction: '', notes: idea.notes || '' }; console.log('Approval change for idea:', ideaData, 'Checked:', approveCheckbox.checked); if (approveCheckbox.checked) { saveAndDisplayMiniCards([ideaData]); } else { sessionIdeas = sessionIdeas.filter(stored => stored.title !== ideaData.title || stored.description !== ideaData.description || stored.reaction !== ideaData.reaction); updateMiniCards(); } }); } ideasContainer.appendChild(card); newIdeaCounter++; }); const generalFeedbackCard = document.createElement('div'); generalFeedbackCard.className = 'general-feedback-card'; generalFeedbackCard.innerHTML = `

General Feedback

`; ideasContainer.appendChild(generalFeedbackCard); } // function processIdeas(text) { try { console.log('Processing ideas, input text length:', text.length); const parsedIdeas = parseLLMResponse(text); if (!Array.isArray(parsedIdeas.newIdeas)) parsedIdeas.newIdeas = []; if (!Array.isArray(parsedIdeas.revisedIdeas)) parsedIdeas.revisedIdeas = []; if (!parsedIdeas.newIdeas.length && !parsedIdeas.revisedIdeas.length) { showNotification('No valid ideas found. Ensure the AI response includes ideas with a Title or Description.', 'error', 5000); return; } lastIdeas = [...parsedIdeas.revisedIdeas, ...parsedIdeas.newIdeas]; lastIdeas.generalFeedbackReaction = parsedIdeas.generalFeedbackReaction; console.log('Processed ideas:', lastIdeas); if (lastIdeas.length < 5 && !parsedIdeas.revisedIdeas.length && lastIdeas.length > 0) { showNotification(`Only ${lastIdeas.length} ideas received. Check AI response formatting for Title, Description, and Rationale fields.`, 'error', 5000); } stage2Active = true; renderIdeas(parsedIdeas); if (stage2) stage2.style.display = 'block'; if (document.getElementById('stage2Actions')) document.getElementById('stage2Actions').style.display = 'block'; if (document.getElementById('approvedIdeas')) document.getElementById('approvedIdeas').style.display = 'block'; if (generatePromptBtn) { generatePromptBtn.disabled = true; generatePromptBtn.title = 'Submit a new idea type or brief to enable'; } if (backToInput) backToInput.style.display = window.innerWidth <= 768 ? 'block' : 'none'; const ideasContainer = document.getElementById('ideasContainer'); if (ideasContainer) { window.scrollTo({ top: ideasContainer.offsetTop, behavior: 'smooth' }); } else { console.error('Ideas container not found for scrolling'); } } catch (e) { showNotification('Error processing response: ' + e.message, 'error', 5000); console.error('Process ideas error:', e); } } // function generateFeedbackPrompt(feedbackData, cards, generalFeedback) { console.log('Generating feedback prompt, feedbackData:', feedbackData, 'generalFeedback:', generalFeedback); lastGeneralFeedback = generalFeedback; let feedbackText = ''; const outputInstructions = ` Output instructions: You MUST generate EXACTLY FIVE new ideas. Each new idea MUST be formatted as a single block with the fields "Title:", "Description:", and "Rationale:", separated by single newlines. The description MUST be a MAXIMUM of 3 sentences, where a sentence ends with a period, exclamation point, or question mark (can be fewer but not more). The rationale MUST be EXACTLY 1 sentence, with no citations or references (e.g., [1], [2]). Use the exact labels "Title:", "Description:", and "Rationale:" with colons, ensuring each label is bolded in the output (e.g., **Title:**). Do not use headers, numbers, bullet points, or any other separators between ideas. Separate each idea block with exactly two blank lines (double newlines). Do not include any introductions, conclusions, extra text, or formatting deviations. Each of the five new ideas MUST represent a radically different approach to the task, with no overlap in themes or execution, and must avoid repeating concepts or themes from any previously provided ideas in this session. Any deviation from this format, including incorrect sentence counts, non-bolded labels, or fewer/more than five ideas, will break the system, so follow it precisely. `; if (feedbackData.some(f => f.feedback) || generalFeedback) { if (generalFeedback) { feedbackText = `General Feedback: ${generalFeedback}\n`; } const specificFeedback = feedbackData.filter(f => f.feedback).map(f => { const card = cards.find(card => card.dataset.ideaNumber === f.ideaNumber.toString()); if (!card) { console.warn(`No card found for idea number ${f.ideaNumber}`); return ''; } const paragraphs = Array.from(card.querySelectorAll('p')); const titleP = paragraphs.find(p => p.textContent.startsWith('Title:')); return `Idea #${f.ideaNumber} (${titleP ? titleP.textContent.replace(/^Title:/, '').trim() : 'Untitled'}): ${f.feedback}`; }).filter(text => text).join('\n'); feedbackText += specificFeedback; return ` You've provided feedback on the following ideas, with General Feedback (if provided) being the most critical input to address, as it reflects your overall sentiment or concerns about the ideas. ${generalFeedback ? 'If General Feedback is present, you MUST include a "General Feedback Reaction:" section (2-3 sentences) before any idea blocks, critically evaluating the feedback’s implications and proposing how it will shape the revised or new ideas.' : ''} For each idea with specific feedback, critically evaluate its relevance, feasibility, and alignment with your goals for promoting Ideasicle X as a platform for virtual, four-person creative teams. Provide a "Reaction to feedback" section (2-3 sentences) for each idea with feedback, explaining whether the feedback is valid and how it will be addressed, or proposing a feasible alternative if the feedback is impractical. Then, revise each idea by rewriting the description (MAXIMUM 3 sentences, where a sentence ends with a period, exclamation point, or question mark) to address the feedback, maintaining the idea’s original title. Additionally, generate EXACTLY FIVE new ideas based on insights from the feedback, adhering to the output instructions below. ${outputInstructions} Format for revised ideas: **Title:** [Original Title for Revised Ideas] **Reaction to feedback:** [2-3 sentences evaluating the feedback] **Description:** [Maximum 3 sentences] Format for new ideas: **Title:** [Unique, Descriptive Idea Title] **Description:** [Maximum 3 sentences] **Rationale:** [Exactly 1 sentence] Your Feedback: ${feedbackText} `; } else { const rejectedIdeas = lastIdeas.map((idea, i) => `Idea #${i + 1} (${idea.title || 'Untitled'}): Rejected by you (no feedback provided).`).join('\n'); return ` You've rejected all previous ideas without providing specific feedback. Review the rejected ideas below, learn from their weaknesses, and generate EXACTLY FIVE new ideas for promoting Ideasicle X as a platform for virtual, four-person creative teams, adhering to the output instructions below. ${outputInstructions} Format for new ideas: **Title:** [Unique, Descriptive Idea Title] **Description:** [Maximum 3 sentences] **Rationale:** [Exactly 1 sentence] Your Rejected Ideas: ${rejectedIdeas} `; } } // function saveAndDisplayMiniCards(ideas) { console.log('Saving and displaying mini-cards, ideas count:', ideas.length); const uniqueIdeas = ideas.filter(idea => !sessionIdeas.some(stored => stored.title === idea.title && stored.description === idea.description && stored.reaction === idea.reaction )); sessionIdeas = [...uniqueIdeas, ...sessionIdeas]; console.log('Updated sessionIdeas:', sessionIdeas); updateMiniCards(); updateApprovedCount(); return uniqueIdeas.length; } // function updateMiniCards() { console.log('Updating mini-cards, sessionIdeas count:', sessionIdeas.length); if (!miniCardsContainer || !noIdeas || !generatePdfBtn) { console.error('Mini cards container, no ideas, or generate PDF button not found'); return; } miniCardsContainer.innerHTML = ''; noIdeas.style.display = sessionIdeas.length ? 'none' : 'block'; generatePdfBtn.style.display = sessionIdeas.length ? 'block' : 'none'; sessionIdeas.forEach((idea, index) => { const card = document.createElement('div'); card.className = `mini-card ${idea.reaction ? 'revised' : ''}`; card.dataset.index = index; card.innerHTML = `

${idea.title || 'Untitled'}

`; card.addEventListener('click', () => { showModal(idea, index); document.body.classList.add('modal-open'); }); miniCardsContainer.appendChild(card); }); } // function showModal(idea, index) { console.log('Showing modal for idea:', idea.title); if (!modalContent || !modalIdeaNotes || !modalApproveCheckbox || !modal) { console.error('Modal content, notes, or approve checkbox not found'); showNotification('Error: Modal elements missing', 'error', 5000); return; } modalContent.innerHTML = `

Idea #${idea.ideaNumber}${idea.reaction ? ' (Revised)' : ''}

Title: ${idea.title || 'Untitled'}

${idea.reaction ? `

Reaction to feedback: ${idea.reaction}

` : ''}

Description: ${idea.description || 'No description'}

${idea.rationale && idea.rationale.trim() && !idea.reaction ? `

Rationale: ${idea.rationale.trim()}

` : ''} `; modalContent.dataset.index = index; modalIdeaNotes.value = idea.notes || ''; modalApproveCheckbox.checked = true; modal.style.display = 'block'; } // function showWarningPrompt(callback) { if (suppressWarning || sessionStorage.getItem('suppressWarning')) { callback(); return; } const dialog = document.createElement('div'); dialog.className = 'dialog'; dialog.innerHTML = `

Generating a new prompt will clear current ideas. Continue?

`; document.body.appendChild(dialog); dialog.style.display = 'block'; const confirmButton = document.getElementById('confirmWarning'); const cancelButton = document.getElementById('cancelWarning'); if (confirmButton) { confirmButton.addEventListener('click', () => { if (document.getElementById('dontShowAgain')?.checked) { sessionStorage.setItem('suppressWarning', 'true'); suppressWarning = true; } document.body.removeChild(dialog); callback(); }); } if (cancelButton) { cancelButton.addEventListener('click', () => { document.body.removeChild(dialog); }); } } // function showInstructionsModal() { console.log('Showing instructions modal'); if (instructionsModal) { instructionsModal.style.display = 'block'; document.body.classList.add('modal-open'); } else { console.error('Instructions modal not found'); showNotification('Instructions modal not found', 'error', 5000); } } // function showTipsModal() { console.log('Showing tips modal'); if (tipsModal) { tipsModal.style.display = 'block'; document.body.classList.add('modal-open'); } else { console.error('Tips modal not found'); showNotification('Tips modal not found', 'error', 5000); } } // function showSuggestionBoxModal() { console.log('Showing suggestion box modal'); try { window.location.href = 'mailto:willb@ideasiclex.com?subject=IX AI Suggestions'; if (suggestionBoxModal) { suggestionBoxModal.style.display = 'block'; document.body.classList.add('modal-open'); } else { console.error('Suggestion box modal not found'); } } catch (e) { console.error('Error opening mailto link:', e); showNotification('Failed to open email client', 'error', 5000); } } // function resetPromptState() { const hasValidBrief = briefInput?.value.trim().length > 0; console.log('Resetting prompt state:', { lastIdeaType, briefLength: briefInput?.value.length, hasValidBrief }); if (generatePromptBtn) { generatePromptBtn.disabled = !lastIdeaType || !hasValidBrief; generatePromptBtn.title = lastIdeaType && hasValidBrief ? 'Generate a new prompt' : 'Submit an idea type and brief to generate a prompt'; console.log('Generate Prompt button disabled:', generatePromptBtn.disabled); } if (briefBuilderBtn) briefBuilderBtn.disabled = !lastIdeaType; if (uploadBriefBtn) uploadBriefBtn.disabled = !lastIdeaType; if (clearInputBtn) clearInputBtn.disabled = !lastIdeaType; } // function clearLlmResponse() { const llmResponse = document.getElementById('llmResponse'); if (llmResponse) { llmResponse.value = ''; console.log('Cleared llmResponse textarea'); } } // function initializeApp() { console.log('App initializing at:', new Date().toLocaleString()); sessionStorage.removeItem('suppressWarning'); suppressWarning = false; const allElementsFound = initializeDOMElements(); if (!allElementsFound) { console.error('One or more critical elements not found'); showNotification('Initialization error: Missing elements. Please check HTML IDs.', 'error', 5000); } // Log potential Squarespace conflicts if (window.YUI || document.querySelector('script[src*="squarespace"]')) { console.warn('Squarespace scripts detected, which may cause conflicts. Consider hosting as a standalone HTML file.'); showNotification('Warning: Squarespace environment detected. Buttons may not work due to script conflicts. Try running as a standalone HTML file.', 'error', 10000); } // Navigation event listeners if (navInstructions) navInstructions.addEventListener('click', showInstructionsModal); if (navTips) navTips.addEventListener('click', showTipsModal); if (navSuggestionBox) navSuggestionBox.addEventListener('click', showSuggestionBoxModal); // Modal close event listeners const closeInstructions = document.getElementById('closeInstructions'); if (closeInstructions) { closeInstructions.addEventListener('click', () => { if (instructionsModal) { instructionsModal.style.display = 'none'; document.body.classList.remove('modal-open'); } }); } const closeTips = document.getElementById('closeTips'); if (closeTips) { closeTips.addEventListener('click', () => { if (tipsModal) { tipsModal.style.display = 'none'; document.body.classList.remove('modal-open'); } }); } const closeSuggestionBox = document.getElementById('closeSuggestionBox'); if (closeSuggestionBox) { closeSuggestionBox.addEventListener('click', () => { if (suggestionBoxModal) { suggestionBoxModal.style.display = 'none'; document.body.classList.remove('modal-open'); } }); } if (closeFeedbackPromptModal) { closeFeedbackPromptModal.addEventListener('click', () => { if (feedbackPromptModal) { feedbackPromptModal.style.display = 'none'; document.body.classList.remove('modal-open'); const llmResponse = document.getElementById('llmResponse'); if (llmResponse) { llmResponse.scrollIntoView({ behavior: 'smooth', block: 'center' }); } else if (stage2) { window.scrollTo({ top: stage2.offsetTop, behavior: 'smooth' }); } } }); } // Brief Builder event listeners if (briefBuilderBtn) { briefBuilderBtn.addEventListener('click', (e) => { e.preventDefault(); console.log('Brief Builder button clicked'); if (briefBuilderModal) { briefBuilderModal.style.display = 'block'; document.body.classList.add('modal-open'); ['briefPromoting', 'briefAudience', 'briefMessage', 'briefExtra'].forEach(id => { const element = document.getElementById(id); if (element) element.value = ''; }); } }); } if (briefBuilderLink) { briefBuilderLink.addEventListener('click', (e) => { e.preventDefault(); briefBuilderBtn?.click(); }); } if (saveBriefBuilder) { saveBriefBuilder.addEventListener('click', () => { console.log('Save Brief Builder clicked'); saveBriefBuilderInput(); }); } if (cancelBriefBuilder) { cancelBriefBuilder.addEventListener('click', () => { console.log('Cancel Brief Builder clicked'); if (briefBuilderModal) { briefBuilderModal.style.display = 'none'; document.body.classList.remove('modal-open'); } }); } // Upload Brief event listeners if (uploadBriefBtn) { uploadBriefBtn.addEventListener('click', (e) => { e.preventDefault(); uploadBriefInput?.click(); }); } if (uploadBriefLink) { uploadBriefLink.addEventListener('click', (e) => { e.preventDefault(); uploadBriefBtn?.click(); }); } if (uploadBriefInput) { uploadBriefInput.addEventListener('change', (e) => { const file = e.target.files[0]; if (file) { handlePdfUpload(file); e.target.value = ''; } }); } // Step 3: Idea Type event listeners (simplified) if (ideaTypeInput && submitIdeaTypeBtn) { ideaTypeInput.addEventListener('input', () => { try { const isValid = ideaTypeInput.value.trim().length > 0; submitIdeaTypeBtn.disabled = !isValid; submitIdeaTypeBtn.title = isValid ? 'Submit idea type' : 'Enter an idea type to submit'; console.log('Idea type input changed, value:', ideaTypeInput.value, 'Submit button enabled:', isValid); } catch (e) { console.error('Error in ideaTypeInput event listener:', e); showNotification('Error handling idea type input', 'error', 5000); } }); submitIdeaTypeBtn.addEventListener('click', () => { try { console.log('Submit Idea Type button clicked, value:', ideaTypeInput.value); const ideaType = ideaTypeInput.value.trim(); if (!ideaType) { showNotification('Please specify the idea type.', 'error', 5000); console.warn('No idea type provided'); return; } lastIdeaType = ideaType; if (briefInput) briefInput.disabled = false; if (briefBuilderBtn) briefBuilderBtn.disabled = false; if (uploadBriefBtn) uploadBriefBtn.disabled = false; if (clearInputBtn) clearInputBtn.disabled = false; submitIdeaTypeBtn.disabled = true; showNotification('Idea type submitted successfully.', 'success', 3000); console.log('Stored idea type:', lastIdeaType); resetPromptState(); setTimeout(() => { if (briefInput) { briefInput.focus(); briefInput.scrollIntoView({ behavior: 'smooth', block: 'center' }); } else { console.error('briefInput not found for focus'); } }, 500); } catch (e) { console.error('Error in submitIdeaTypeBtn event listener:', e); showNotification('Error submitting idea type', 'error', 5000); } }); } // Brief Input event listener if (briefInput) { briefInput.addEventListener('input', () => { try { console.log('Brief input changed, value length:', briefInput.value.length); resetPromptState(); } catch (e) { console.error('Error in briefInput event listener:', e); showNotification('Error handling brief input', 'error', 5000); } }); } // Generate Prompt event listener if (generatePromptBtn) { generatePromptBtn.addEventListener('click', () => { try { console.log('Generate Prompt button clicked at:', new Date().toLocaleString()); if (!briefInput) { console.error('Brief input element not found'); showNotification('Error: Creative brief input missing', 'error', 5000); return; } const brief = briefInput.value.trim(); if (!brief) { console.warn('No brief provided'); showNotification('Please enter a creative brief', 'error', 5000); return; } if (!lastIdeaType) { console.warn('No idea type provided'); showNotification('Please submit an idea type in Step 3', 'error', 5000); return; } const hallucinationLevel = document.querySelector('input[name="hallucinationLevel"]:checked')?.value; const aiEngine = document.querySelector('input[name="aiEngine"]:checked')?.value; if (!hallucinationLevel) { console.warn('No hallucination level selected'); showNotification('Please select a hallucination level', 'error', 5000); return; } if (!aiEngine) { console.warn('No AI engine selected'); showNotification('Please select an AI engine', 'error', 5000); return; } console.log('Generating prompt with brief length:', brief.length, 'ideaType:', lastIdeaType, 'hallucinationLevel:', hallucinationLevel, 'aiEngine:', aiEngine); const fullPrompt = generatePrompt(brief, lastIdeaType); console.log('Prompt generated, length:', fullPrompt.length); const copyPrompt = () => { lastBrief = brief; lastHallucinationLevel = hallucinationLevel; lastAiEngine = aiEngine; stage2Active = false; resetPromptState(); clearLlmResponse(); showAiEngineModal(aiEngine, fullPrompt, false); }; if (stage2Active && (lastBrief !== brief || lastHallucinationLevel !== hallucinationLevel || lastAiEngine !== aiEngine || lastIdeaType !== ideaTypeInput.value.trim())) { console.log('Showing warning prompt due to active stage 2'); showWarningPrompt(copyPrompt); } else { console.log('No warning needed, proceeding to copy prompt'); copyPrompt(); } } catch (e) { console.error('Generate prompt error:', e); showNotification('Error generating prompt: ' + e.message, 'error', 5000); } }); } // Clear Input event listener if (clearInputBtn) { clearInputBtn.addEventListener('click', () => { try { console.log('Clear button clicked'); resetApp(true); resetPromptState(); showNotification('Input Cleared', 'success', 3000); } catch (e) { showNotification('Error clearing input: ' + e.message, 'error', 5000); console.error('Clear input error:', e); } }); } // Process Button event listener if (processBtn) { processBtn.addEventListener('click', () => { try { const text = document.getElementById('llmResponse')?.value.trim(); console.log('Process button clicked, textarea value length:', text?.length || 0); if (!text) { showNotification('Please paste an AI response.', 'error', 5000); return; } processIdeas(text); } catch (e) { showNotification('Error processing response: ' + e.message, 'error', 5000); console.error('Process error:', e); } }); } // Generate Feedback Button event listener if (generateFeedbackBtn) { generateFeedbackBtn.addEventListener('click', () => { try { console.log('Generate Feedback Prompt clicked'); const feedbackData = []; const cards = Array.from(document.getElementById('ideasContainer')?.getElementsByClassName('idea-card') || []); if (!cards.length) { showNotification('No idea cards found. Please ensure ideas are displayed.', 'error', 5000); console.error('No idea cards found in ideasContainer'); return; } for (let i = 0; i < cards.length; i++) { const feedbackInput = document.getElementById(`feedback-${i}`); if (!feedbackInput) { console.warn(`Feedback input not found for index ${i}`); feedbackData.push({ ideaNumber: cards[i].dataset.ideaNumber, feedback: '' }); continue; } const feedback = feedbackInput.value.trim(); console.log('Card', i, 'Feedback:', feedback, 'Idea Number:', cards[i].dataset.ideaNumber); feedbackData.push({ ideaNumber: parseInt(cards[i].dataset.ideaNumber), feedback }); } const generalFeedbackInput = document.getElementById('generalFeedback'); const generalFeedback = generalFeedbackInput ? generalFeedbackInput.value.trim() : ''; console.log('General feedback:', generalFeedback); if (!feedbackData.some(f => f.feedback) && !generalFeedback) { showNotification('Please provide feedback for at least one idea or general feedback.', 'error', 5000); console.warn('No specific or general feedback provided'); return; } const feedbackPrompt = generateFeedbackPrompt(feedbackData, cards, generalFeedback); console.log('Generated feedback prompt length:', feedbackPrompt.length); navigator.clipboard.writeText(feedbackPrompt).then(() => { console.log('Feedback prompt copied to clipboard'); document.getElementById('llmResponse').value = ''; if (feedbackPromptModal && feedbackAiEngineName && closeFeedbackPromptModal) { feedbackAiEngineName.textContent = lastAiEngine; feedbackPromptModal.style.display = 'block'; document.body.classList.add('modal-open'); } else { console.error('Feedback prompt modal elements missing'); showNotification('Error: Feedback prompt modal elements missing', 'error', 5000); } }).catch(err => { console.error('Error copying feedback prompt:', err.message); showNotification('Clipboard access failed.', 'error', 5000); }); } catch (e) { console.error('Generate feedback error:', e); showNotification('Error generating feedback prompt: ' + e.message, 'error', 5000); } }); } // Generate PDF Button event listener if (generatePdfBtn) { generatePdfBtn.addEventListener('click', generatePDF); } // Modal Close event listener if (modalClose) { modalClose.addEventListener('click', () => { try { const index = parseInt(modalContent.dataset.index); const notes = modalIdeaNotes.value.trim(); if (index >= 0 && index < sessionIdeas.length) { sessionIdeas[index].notes = notes; console.log('Saved notes for idea:', sessionIdeas[index].title, 'Notes:', notes); } if (modal) { modal.style.display = 'none'; document.body.classList.remove('modal-open'); } } catch (e) { console.error('Error closing modal:', e); showNotification('Error saving notes: ' + e.message, 'error', 5000); } }); } // Modal Approve Checkbox event listener if (modalApproveCheckbox) { modalApproveCheckbox.addEventListener('click', () => { try { const index = parseInt(modalContent.dataset.index); console.log('Modal approve checkbox changed, index:', index, 'Checked:', modalApproveCheckbox.checked); if (!modalApproveCheckbox.checked) { if (index >= 0 && index < sessionIdeas.length) { const ideaNumber = sessionIdeas[index].ideaNumber; const ideasContainer = document.getElementById('ideasContainer'); const ideaCard = Array.from(ideasContainer.getElementsByClassName('idea-card')).find( card => card.dataset.ideaNumber === ideaNumber ); if (ideaCard) { const checkbox = ideaCard.querySelector(`input[id^="approve-"]`); if (checkbox) { checkbox.checked = false; console.log(`Unchecked checkbox for idea #${ideaNumber} in ideasContainer`); } } sessionIdeas.splice(index, 1); updateMiniCards(); updateApprovedCount(); if (modal) { modal.style.display = 'none'; document.body.classList.remove('modal-open'); } showNotification('Idea Unapproved', 'success', 3000); } } else { const notes = modalIdeaNotes.value.trim(); if (index >= 0 && index < sessionIdeas.length) { sessionIdeas[index].notes = notes; console.log('Saved notes for idea:', sessionIdeas[index].title, 'Notes:', notes); } } } catch (e) { showNotification('Error updating approval status: ' + e.message, 'error', 5000); console.error('Modal approve error:', e); } }); } // Modal Idea Notes event listener if (modalIdeaNotes) { modalIdeaNotes.addEventListener('input', () => { try { const index = parseInt(modalContent.dataset.index); const notes = modalIdeaNotes.value.trim(); if (index >= 0 && index < sessionIdeas.length) { sessionIdeas[index].notes = notes; console.log('Notes updated for idea:', sessionIdeas[index].title, 'Notes:', notes); } } catch (e) { console.error('Error updating notes:', e); } }); } // Hallucination Level Radio event listeners document.querySelectorAll('input[name="hallucinationLevel"]').forEach(radio => { radio.addEventListener('change', () => { try { console.log('Hallucination level changed to:', radio.value); resetPromptState(); clearLlmResponse(); } catch (e) { console.error('Error in hallucinationLevel event listener:', e); } }); }); // AI Engine Radio event listeners document.querySelectorAll('input[name="aiEngine"]').forEach(radio => { radio.addEventListener('change', () => { try { console.log('AI engine changed to:', radio.value); resetPromptState(); clearLlmResponse(); } catch (e) { console.error('Error in aiEngine event listener:', e); } }); }); // Back to Input event listener if (backToInput) { backToInput.addEventListener('click', () => { try { if (stage1) window.scrollTo({ top: stage1.offsetTop, behavior: 'smooth' }); } catch (e) { console.error('Error in backToInput event listener:', e); } }); } // Window Resize event listener window.addEventListener('resize', () => { try { if (backToInput) backToInput.style.display = window.innerWidth <= 768 ? 'block' : 'none'; } catch (e) { console.error('Error in resize event listener:', e); } }); // Before Unload event listener window.addEventListener('beforeunload', e => { if (sessionIdeas.length) { e.preventDefault(); e.returnValue = 'Don’t forget to create a PDF!'; } }); // Initialize button states resetPromptState(); } // window.addEventListener('load', () => { try { initializeApp(); } catch (e) { console.error('Initialization failed:', e); showNotification('Failed to initialize app. Please check console for details.', 'error', 5000); } });