const API_URL = window.location.origin; const questions = [ { id: 'startup_name', section: 'A. BASIC STARTUP INFORMATION', text: "What is your startup's name?", type: 'text', required: true }, { id: 'industry', section: 'A. BASIC STARTUP INFORMATION', text: 'Which industry/domain does your startup operate in?', subtitle: 'e.g., fintech, AI/ML, SaaS, edtech, e-commerce, healthtech, manufacturing, HR-tech, gaming, etc.', type: 'text', required: true }, { id: 'description', section: 'A. BASIC STARTUP INFORMATION', text: 'Describe your startup in one or two sentences', subtitle: 'This helps the model understand your exact business model', type: 'textarea', required: true }, { id: 'company_structure', section: 'A. BASIC STARTUP INFORMATION', text: 'What is your current company structure?', type: 'buttons', options: [ 'Not registered yet', 'Sole proprietorship', 'Partnership', 'LLP', 'Private Limited Company', 'Public Limited', 'One Person Company' ], required: true }, { id: 'num_founders', section: 'B. FOUNDERS & OWNERSHIP', text: 'How many founders does your startup have?', type: 'number', required: true }, { id: 'founder_agreement', section: 'B. FOUNDERS & OWNERSHIP', text: 'Do you have a founder agreement in place?', type: 'buttons', options: ['Yes', 'No'], required: true }, { id: 'ownership_splits', section: 'B. FOUNDERS & OWNERSHIP', text: 'Should the documents consider ownership splits or equity distribution?', type: 'buttons', options: ['Yes', 'No'], required: true }, { id: 'has_employees', section: 'C. EMPLOYEES & TEAM STRUCTURE', text: 'Do you currently have employees?', type: 'buttons', options: ['Yes', 'No'], required: true }, { id: 'num_employees', section: 'C. EMPLOYEES & TEAM STRUCTURE', text: 'How many employees or interns?', type: 'number', subtitle: 'Skip if you answered No to previous question', required: false, conditionalOn: { field: 'has_employees', value: 'Yes' } }, { id: 'plan_to_hire', section: 'C. EMPLOYEES & TEAM STRUCTURE', text: 'Do you plan to hire soon?', type: 'buttons', options: ['Yes', 'No'], required: true }, { id: 'product_type', section: 'D. PRODUCT / TECH / OPERATIONS', text: 'What type of product/service do you offer?', type: 'buttons', options: [ 'Software app / SaaS', 'AI model/service', 'Physical product / hardware', 'Advisory/consulting', 'Marketplace', 'Platform (B2B/B2C)' ], required: true }, { id: 'collects_user_data', section: 'D. PRODUCT / TECH / OPERATIONS', text: 'Do you collect or process user data?', type: 'buttons', options: ['Yes', 'No'], required: true }, { id: 'data_type', section: 'D. PRODUCT / TECH / OPERATIONS', text: 'What kind of data?', subtitle: 'Select all that apply', type: 'checkboxes', options: ['Personal', 'Financial', 'Medical', 'Behavioural', 'Other'], required: false, conditionalOn: { field: 'collects_user_data', value: 'Yes' } }, { id: 'primary_customers', section: 'E. CUSTOMERS & MARKET', text: 'Who are your primary customers?', type: 'buttons', options: ['Individuals (B2C)', 'Businesses (B2B)', 'Government', 'Mixed'], required: true }, { id: 'has_vendors', section: 'E. CUSTOMERS & MARKET', text: 'Do you work with vendors/partners?', type: 'buttons', options: ['Yes', 'No'], required: true }, { id: 'client_contracts', section: 'E. CUSTOMERS & MARKET', text: 'Do you plan to onboard clients under contracts?', type: 'buttons', options: ['Yes', 'No'], required: true }, { id: 'has_ip', section: 'F. INTELLECTUAL PROPERTY (IP)', text: 'Do you have any proprietary technology, designs, or brand assets?', type: 'buttons', options: ['Yes', 'No'], required: true }, { id: 'ip_types', section: 'F. INTELLECTUAL PROPERTY (IP)', text: 'What type of IP protection do you need?', subtitle: 'Select all that apply', type: 'checkboxes', options: ['Patents', 'Copyrights', 'Trademarks', 'Licensing agreements'], required: false, conditionalOn: { field: 'has_ip', value: 'Yes' } }, { id: 'startup_stage', section: 'G. FINANCIALS & FUNDRAISING', text: 'What stage is your startup currently in?', type: 'buttons', options: ['Idea', 'Validation / MVP', 'Early revenue', 'Scaling'], required: true }, { id: 'raising_funds', section: 'G. FINANCIALS & FUNDRAISING', text: 'Have you raised or are you planning to raise funds?', type: 'buttons', options: ['Yes', 'No'], required: true }, { id: 'funding_type', section: 'G. FINANCIALS & FUNDRAISING', text: 'What type of funding?', type: 'buttons', options: ['Angel', 'Seed', 'VC', 'Grant', 'Crowdfunding', 'Multiple'], required: false, conditionalOn: { field: 'raising_funds', value: 'Yes' } }, { id: 'considering_esops', section: 'G. FINANCIALS & FUNDRAISING', text: 'Are you considering ESOPs?', type: 'buttons', options: ['Yes', 'No'], required: true }, { id: 'regulated_industry', section: 'H. RISK / COMPLIANCE NEEDS', text: 'Do you operate in a regulated industry?', subtitle: 'Select all that apply', type: 'checkboxes', options: ['Fintech', 'Health', 'Logistics', 'Finance/Banking', 'Food', 'Education', 'None'], required: true }, { id: 'operates_internationally', section: 'H. RISK / COMPLIANCE NEEDS', text: 'Does your startup operate internationally?', type: 'buttons', options: ['Yes', 'No'], required: true }, { id: 'countries', section: 'H. RISK / COMPLIANCE NEEDS', text: 'List the countries', subtitle: 'Separate countries with commas', type: 'text', required: false, conditionalOn: { field: 'operates_internationally', value: 'Yes' } }, { id: 'turnover_exceeds_20l', section: 'I. GST QUESTIONS', text: 'Do you expect your annual turnover to exceed INR 20 lakh?', subtitle: 'GST registration becomes mandatory above this threshold', type: 'buttons', options: ['Yes', 'No', 'Unsure'], required: true }, { id: 'sells_products_services', section: 'I. GST QUESTIONS', text: 'Do you sell physical products, digital services, or both?', subtitle: 'GST rates vary; product sellers must generate GST-compliant invoices', type: 'buttons', options: ['Physical products', 'Digital services', 'Both'], required: true }, { id: 'sells_outside_india', section: 'I. GST QUESTIONS', text: 'Do you sell your product/services outside India?', subtitle: 'If yes ā GST LUT, export documentation, zero-rated supply requirements', type: 'buttons', options: ['Yes', 'No'], required: true }, { id: 'sells_through_platforms', section: 'I. GST QUESTIONS', text: 'Do you sell through online platforms/marketplaces?', subtitle: 'E-commerce operators have special GST compliance and TCS rules', type: 'buttons', options: ['Yes', 'No'], required: true }, { id: 'buys_for_business', section: 'I. GST QUESTIONS', text: 'Do you buy goods/services for business (ITC eligibility)?', subtitle: 'To generate ITC-related compliance recommendations', type: 'buttons', options: ['Yes', 'No', 'Unsure'], required: true }, { id: 'gst_registration_timing', section: 'I. GST QUESTIONS', text: 'Do you want GST registration done immediately?', subtitle: 'Helps include GSTIN and registration documents in the list', type: 'buttons', options: ['Yes', 'No', 'Later'], required: true } ]; // ========================================== // STATE MANAGEMENT // ========================================== let currentQuestionIndex = 0; let answers = {}; let generatedDocuments = null; // ========================================== // NAVIGATION FUNCTIONS // ========================================== function showSection(sectionId) { document.querySelectorAll('.section').forEach(section => { section.classList.remove('active'); }); document.getElementById(sectionId).classList.add('active'); } function startQuestionnaire() { showSection('questionPage'); currentQuestionIndex = 0; answers = {}; displayQuestion(); } function startOver() { if (confirm('Are you sure you want to start over? This will clear all your answers.')) { currentQuestionIndex = 0; answers = {}; generatedDocuments = null; showSection('landingPage'); } } // ========================================== // QUESTION DISPLAY LOGIC // ========================================== function displayQuestion() { const question = questions[currentQuestionIndex]; // Check if question is conditional if (question.conditionalOn) { const { field, value } = question.conditionalOn; if (answers[field] !== value) { // Skip this question if (currentQuestionIndex < questions.length - 1) { currentQuestionIndex++; displayQuestion(); } else { submitAnswers(); } return; } } // Update progress updateProgress(); // Update question text document.getElementById('questionText').textContent = question.text; document.getElementById('questionSubtitle').textContent = question.subtitle || ''; // Hide all input types document.getElementById('textInput').style.display = 'none'; document.getElementById('textareaInput').style.display = 'none'; document.getElementById('numberInput').style.display = 'none'; document.getElementById('buttonOptions').style.display = 'none'; document.getElementById('checkboxOptions').style.display = 'none'; // Show appropriate input type switch (question.type) { case 'text': document.getElementById('textInput').style.display = 'block'; document.getElementById('textAnswer').value = answers[question.id] || ''; document.getElementById('textAnswer').focus(); break; case 'textarea': document.getElementById('textareaInput').style.display = 'block'; document.getElementById('textareaAnswer').value = answers[question.id] || ''; document.getElementById('textareaAnswer').focus(); break; case 'number': document.getElementById('numberInput').style.display = 'block'; document.getElementById('numberAnswer').value = answers[question.id] || ''; document.getElementById('numberAnswer').focus(); break; case 'buttons': displayButtonOptions(question); break; case 'checkboxes': displayCheckboxOptions(question); break; } // Show/hide back button document.getElementById('backBtn').style.display = currentQuestionIndex > 0 ? 'flex' : 'none'; // Animate card entrance const card = document.getElementById('questionCard'); card.style.animation = 'none'; setTimeout(() => { card.style.animation = 'slideUp 0.4s ease-out'; }, 10); } function displayButtonOptions(question) { const container = document.getElementById('buttonOptions'); container.style.display = 'grid'; container.innerHTML = ''; question.options.forEach(option => { const button = document.createElement('button'); button.className = 'option-btn'; button.textContent = option; button.onclick = () => selectOption(question.id, option, button); if (answers[question.id] === option) { button.classList.add('selected'); } container.appendChild(button); }); } function displayCheckboxOptions(question) { const container = document.getElementById('checkboxOptions'); container.style.display = 'flex'; container.innerHTML = ''; const existingAnswers = answers[question.id] || []; question.options.forEach((option, index) => { const wrapper = document.createElement('div'); wrapper.className = 'checkbox-option'; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.id = `checkbox_${index}`; checkbox.value = option; checkbox.checked = existingAnswers.includes(option); const label = document.createElement('label'); label.htmlFor = `checkbox_${index}`; label.textContent = option; wrapper.appendChild(checkbox); wrapper.appendChild(label); if (checkbox.checked) { wrapper.classList.add('selected'); } wrapper.onclick = () => { checkbox.checked = !checkbox.checked; wrapper.classList.toggle('selected', checkbox.checked); }; container.appendChild(wrapper); }); } function selectOption(questionId, value, button) { answers[questionId] = value; // Update button states document.querySelectorAll('.option-btn').forEach(btn => { btn.classList.remove('selected'); }); button.classList.add('selected'); } function updateProgress() { const progress = ((currentQuestionIndex + 1) / questions.length) * 100; document.getElementById('progressFill').style.width = `${progress}%`; document.getElementById('questionCounter').textContent = `Question ${currentQuestionIndex + 1} of ${questions.length}`; } // ========================================== // ANSWER COLLECTION // ========================================== function getCurrentAnswer() { const question = questions[currentQuestionIndex]; switch (question.type) { case 'text': return document.getElementById('textAnswer').value.trim(); case 'textarea': return document.getElementById('textareaAnswer').value.trim(); case 'number': return document.getElementById('numberAnswer').value; case 'buttons': return answers[question.id] || null; case 'checkboxes': const checkboxes = document.querySelectorAll('#checkboxOptions input[type="checkbox"]:checked'); return Array.from(checkboxes).map(cb => cb.value); } } function validateAnswer(answer) { const question = questions[currentQuestionIndex]; if (!question.required) { return true; } if (question.type === 'checkboxes') { return answer && answer.length > 0; } return answer !== null && answer !== '' && answer !== undefined; } // ========================================== // NAVIGATION HANDLERS // ========================================== function nextQuestion() { const answer = getCurrentAnswer(); if (!validateAnswer(answer)) { alert('Please provide an answer before continuing.'); return; } // Save answer const question = questions[currentQuestionIndex]; answers[question.id] = answer; // Move to next question or submit if (currentQuestionIndex < questions.length - 1) { currentQuestionIndex++; displayQuestion(); } else { submitAnswers(); } } function goBack() { if (currentQuestionIndex > 0) { currentQuestionIndex--; // Skip conditional questions when going back const question = questions[currentQuestionIndex]; if (question.conditionalOn) { const { field, value } = question.conditionalOn; if (answers[field] !== value) { goBack(); return; } } displayQuestion(); } } // ========================================== // API SUBMISSION // ========================================== async function submitAnswers() { console.log('\n' + '='.repeat(80)); console.log('š STARTING DOCUMENT GENERATION PROCESS'); console.log('='.repeat(80)); console.log('š Timestamp:', new Date().toLocaleTimeString()); showSection('loadingPage'); animateLoadingSteps(); try { // Format answers for the prompt console.log('\nš Step 1: Building prompt from user answers...'); const prompt = buildPrompt(answers); console.log(' ā Prompt built successfully'); console.log(' - Prompt length:', prompt.length, 'characters'); console.log(' - Prompt preview:', prompt.substring(0, 200) + '...'); const requestParams = { prompt: prompt, max_new_tokens: 100, // Very short to avoid timeout temperature: 0.3, // Lower for more factual output top_p: 0.85 }; console.log('\nš Step 2: Preparing API request...'); console.log(' - API URL:', `${API_URL}/api/generate`); console.log(' - Max tokens:', requestParams.max_new_tokens); console.log(' - Temperature:', requestParams.temperature); console.log(' - Top P:', requestParams.top_p); console.log('\nš Step 3: Sending POST request to backend...'); const requestStartTime = Date.now(); const response = await fetch(`${API_URL}/api/generate`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(requestParams) }); const requestEndTime = Date.now(); const requestDuration = ((requestEndTime - requestStartTime) / 1000).toFixed(2); console.log('\nš„ Step 4: Response received from backend'); console.log(' - Response status:', response.status, response.statusText); console.log(' - Response time:', requestDuration, 'seconds'); console.log(' - Response OK:', response.ok); if (!response.ok) { console.error(' ā Backend returned error status'); throw new Error(`HTTP ${response.status}: ${response.statusText}`); } console.log('\nš Step 5: Parsing JSON response...'); const data = await response.json(); console.log(' ā JSON parsed successfully'); // Parse the generated text as JSON const generatedText = data.generated_text; console.log('\nš Step 6: Processing generated text...'); console.log(' - Generated text length:', generatedText.length, 'characters'); console.log(' - Generated text preview:', generatedText.substring(0, 200) + '...'); console.log('\nš Step 7: Parsing generated documents from text...'); generatedDocuments = parseGeneratedDocuments(generatedText); console.log(' ā Documents parsed successfully'); console.log(' - Number of documents:', generatedDocuments.length); // Display results console.log('\nšØ Step 8: Displaying results to user...'); displayResults(); console.log(' ā Results displayed successfully'); console.log('\nā DOCUMENT GENERATION COMPLETED SUCCESSFULLY'); console.log('ā±ļø Total time:', requestDuration, 'seconds'); console.log('='.repeat(80) + '\n'); } catch (error) { console.error('\nā ERROR OCCURRED DURING GENERATION:'); console.error(' - Error type:', error.name); console.error(' - Error message:', error.message); console.error(' - Stack trace:', error.stack); console.log('='.repeat(80) + '\n'); alert(`Error generating documents: ${error.message}\n\nPlease try again.`); showSection('questionPage'); } } function buildPrompt(answers) { // Build a structured prompt based on the answers let prompt = `You are a legal document advisor for startups. Based on the following information about a startup, generate a comprehensive JSON list of required legal documents.\n\n`; prompt += `STARTUP INFORMATION:\n`; prompt += `- Name: ${answers.startup_name}\n`; prompt += `- Industry: ${answers.industry}\n`; prompt += `- Description: ${answers.description}\n`; prompt += `- Company Structure: ${answers.company_structure}\n`; prompt += `- Number of Founders: ${answers.num_founders}\n`; prompt += `- Has Founder Agreement: ${answers.founder_agreement}\n`; prompt += `- Consider Ownership Splits: ${answers.ownership_splits}\n`; prompt += `- Has Employees: ${answers.has_employees}\n`; if (answers.num_employees) { prompt += `- Number of Employees: ${answers.num_employees}\n`; } prompt += `- Plans to Hire: ${answers.plan_to_hire}\n`; prompt += `- Product Type: ${answers.product_type}\n`; prompt += `- Collects User Data: ${answers.collects_user_data}\n`; if (answers.data_type) { prompt += `- Data Types: ${Array.isArray(answers.data_type) ? answers.data_type.join(', ') : answers.data_type}\n`; } prompt += `- Primary Customers: ${answers.primary_customers}\n`; prompt += `- Works with Vendors: ${answers.has_vendors}\n`; prompt += `- Client Contracts: ${answers.client_contracts}\n`; prompt += `- Has Intellectual Property: ${answers.has_ip}\n`; if (answers.ip_types) { prompt += `- IP Types: ${Array.isArray(answers.ip_types) ? answers.ip_types.join(', ') : answers.ip_types}\n`; } prompt += `- Startup Stage: ${answers.startup_stage}\n`; prompt += `- Raising Funds: ${answers.raising_funds}\n`; if (answers.funding_type) { prompt += `- Funding Type: ${answers.funding_type}\n`; } prompt += `- Considering ESOPs: ${answers.considering_esops}\n`; prompt += `- Regulated Industries: ${Array.isArray(answers.regulated_industry) ? answers.regulated_industry.join(', ') : answers.regulated_industry}\n`; prompt += `- Operates Internationally: ${answers.operates_internationally}\n`; if (answers.countries) { prompt += `- Countries: ${answers.countries}\n`; } prompt += `- Turnover Exceeds 20L: ${answers.turnover_exceeds_20l}\n`; prompt += `- Sells: ${answers.sells_products_services}\n`; prompt += `- Sells Outside India: ${answers.sells_outside_india}\n`; prompt += `- Sells Through Platforms: ${answers.sells_through_platforms}\n`; prompt += `- Buys for Business: ${answers.buys_for_business}\n`; prompt += `- GST Registration Timing: ${answers.gst_registration_timing}\n\n`; prompt += `Generate a JSON array of document objects with the following structure:\n`; prompt += `[\n`; prompt += ` {\n`; prompt += ` "name": "Document Name",\n`; prompt += ` "description": "Brief description of what this document does",\n`; prompt += ` "why_needed": "Why this startup specifically needs this document",\n`; prompt += ` "risk_if_missing": "What risks the startup faces without this document",\n`; prompt += ` "priority": "critical|high|medium|low",\n`; prompt += ` "category": "legal|compliance|financial|operational|ip",\n`; prompt += ` "stakeholders": ["stakeholder1", "stakeholder2"],\n`; prompt += ` "is_optional": false\n`; prompt += ` }\n`; prompt += `]\n\n`; prompt += `Return ONLY the JSON array, no additional text.`; return prompt; } function parseGeneratedDocuments(text) { try { // Try to find JSON in the text const jsonMatch = text.match(/\[[\s\S]*\]/); if (jsonMatch) { return JSON.parse(jsonMatch[0]); } // If no JSON found, try parsing the whole text return JSON.parse(text); } catch (error) { console.error('Error parsing JSON:', error); console.log('Generated text:', text); // Return a fallback structure return [ { name: "Error Parsing Response", description: "The AI generated a response but it couldn't be parsed. Please try again.", why_needed: "N/A", risk_if_missing: "N/A", priority: "high", category: "legal", stakeholders: [], is_optional: false } ]; } } function animateLoadingSteps() { const steps = document.querySelectorAll('.loading-step'); setTimeout(() => { steps[0].classList.remove('active'); steps[1].classList.add('active'); }, 2000); setTimeout(() => { steps[1].classList.remove('active'); steps[2].classList.add('active'); }, 4000); } // ========================================== // RESULTS DISPLAY // ========================================== function displayResults() { showSection('resultsPage'); const requiredDocs = generatedDocuments.filter(doc => !doc.is_optional); const optionalDocs = generatedDocuments.filter(doc => doc.is_optional); // Display required documents const grid = document.getElementById('documentsGrid'); grid.innerHTML = ''; requiredDocs.forEach((doc, index) => { const card = createDocumentCard(doc, index); grid.appendChild(card); }); // Display optional documents if any if (optionalDocs.length > 0) { document.getElementById('optionalSection').style.display = 'block'; const optionalGrid = document.getElementById('optionalDocumentsGrid'); optionalGrid.innerHTML = ''; optionalDocs.forEach((doc, index) => { const card = createDocumentCard(doc, index + requiredDocs.length); optionalGrid.appendChild(card); }); } else { document.getElementById('optionalSection').style.display = 'none'; } } function createDocumentCard(doc, index) { const card = document.createElement('div'); card.className = 'document-card'; card.style.animationDelay = `${index * 0.1}s`; const priorityClass = doc.priority.toLowerCase(); card.innerHTML = `
${doc.description}