Download static/app.js from KASHH-4/Copy: direct link, hf CLI and curl.
- Browser
- Download file 34.7 kB
-
https://huggingface.co/spaces/KASHH-4/Copy/resolve/main/static/app.js
- Command line
-
hf download hf://spaces/KASHH-4/Copy/static/app.js
-
curl -L -o app.js https://huggingface.co/spaces/KASHH-4/Copy/resolve/main/static/app.js
34.7 kB
| 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 = ` | |
| <div class="card-header"> | |
| <h3 class="card-title">${doc.name}</h3> | |
| <span class="priority-badge ${priorityClass}">${doc.priority}</span> | |
| </div> | |
| <span class="category-badge">${doc.category}</span> | |
| <p class="card-description">${doc.description}</p> | |
| <div class="card-section"> | |
| <div class="card-section-title">Why You Need This</div> | |
| <div class="card-section-content">${doc.why_needed}</div> | |
| </div> | |
| <div class="card-section"> | |
| <div class="card-section-title">Risk If Missing</div> | |
| <div class="card-section-content risk">${doc.risk_if_missing}</div> | |
| </div> | |
| ${doc.stakeholders && doc.stakeholders.length > 0 ? ` | |
| <div class="card-section"> | |
| <div class="card-section-title">Stakeholders</div> | |
| <div class="stakeholders-list"> | |
| ${doc.stakeholders.map(s => `<span class="stakeholder-tag">${s}</span>`).join('')} | |
| </div> | |
| </div> | |
| ` : ''} | |
| `; | |
| return card; | |
| } | |
| // ========================================== | |
| // PDF GENERATION | |
| // ========================================== | |
| function downloadPDF() { | |
| const { jsPDF } = window.jspdf; | |
| const doc = new jsPDF(); | |
| let yPos = 20; | |
| const pageHeight = doc.internal.pageSize.height; | |
| const margin = 20; | |
| const lineHeight = 7; | |
| // Title | |
| doc.setFontSize(20); | |
| doc.setTextColor(26, 35, 126); | |
| doc.text('Legal Document Requirements', margin, yPos); | |
| yPos += 15; | |
| // Startup info | |
| doc.setFontSize(12); | |
| doc.setTextColor(100, 100, 100); | |
| doc.text(`${answers.startup_name} - ${answers.industry}`, margin, yPos); | |
| yPos += 10; | |
| doc.setFontSize(10); | |
| doc.text(`Generated on ${new Date().toLocaleDateString()}`, margin, yPos); | |
| yPos += 15; | |
| // Documents | |
| const requiredDocs = generatedDocuments.filter(doc => !doc.is_optional); | |
| const optionalDocs = generatedDocuments.filter(doc => doc.is_optional); | |
| // Required documents | |
| doc.setFontSize(14); | |
| doc.setTextColor(26, 35, 126); | |
| doc.text('Required Documents', margin, yPos); | |
| yPos += 10; | |
| requiredDocs.forEach((document, index) => { | |
| // Check if we need a new page | |
| if (yPos > pageHeight - 40) { | |
| doc.addPage(); | |
| yPos = 20; | |
| } | |
| // Document number and name | |
| doc.setFontSize(12); | |
| doc.setTextColor(0, 0, 0); | |
| doc.text(`${index + 1}. ${document.name}`, margin, yPos); | |
| yPos += lineHeight; | |
| // Priority badge | |
| doc.setFontSize(9); | |
| const priorityColors = { | |
| critical: [239, 68, 68], | |
| high: [245, 158, 11], | |
| medium: [59, 130, 246], | |
| low: [16, 185, 129] | |
| }; | |
| const color = priorityColors[document.priority.toLowerCase()] || [100, 100, 100]; | |
| doc.setTextColor(...color); | |
| doc.text(`Priority: ${document.priority.toUpperCase()}`, margin + 5, yPos); | |
| yPos += lineHeight; | |
| // Description | |
| doc.setFontSize(10); | |
| doc.setTextColor(80, 80, 80); | |
| const descLines = doc.splitTextToSize(document.description, 170); | |
| doc.text(descLines, margin + 5, yPos); | |
| yPos += descLines.length * lineHeight; | |
| yPos += 5; | |
| }); | |
| // Optional documents | |
| if (optionalDocs.length > 0) { | |
| if (yPos > pageHeight - 60) { | |
| doc.addPage(); | |
| yPos = 20; | |
| } | |
| yPos += 10; | |
| doc.setFontSize(14); | |
| doc.setTextColor(26, 35, 126); | |
| doc.text('Optional Documents', margin, yPos); | |
| yPos += 10; | |
| optionalDocs.forEach((document, index) => { | |
| if (yPos > pageHeight - 40) { | |
| doc.addPage(); | |
| yPos = 20; | |
| } | |
| doc.setFontSize(12); | |
| doc.setTextColor(0, 0, 0); | |
| doc.text(`${index + 1}. ${document.name}`, margin, yPos); | |
| yPos += lineHeight; | |
| doc.setFontSize(10); | |
| doc.setTextColor(80, 80, 80); | |
| const descLines = doc.splitTextToSize(document.description, 170); | |
| doc.text(descLines, margin + 5, yPos); | |
| yPos += descLines.length * lineHeight + 5; | |
| }); | |
| } | |
| // Footer on last page | |
| const totalPages = doc.internal.getNumberOfPages(); | |
| for (let i = 1; i <= totalPages; i++) { | |
| doc.setPage(i); | |
| doc.setFontSize(8); | |
| doc.setTextColor(150, 150, 150); | |
| doc.text( | |
| 'Generated by LegalDocs AI - This is informational guidance only, not legal advice', | |
| margin, | |
| pageHeight - 10 | |
| ); | |
| doc.text(`Page ${i} of ${totalPages}`, pageHeight - margin, pageHeight - 10); | |
| } | |
| doc.save(`${answers.startup_name}_legal_documents.pdf`); | |
| } | |
| // ========================================== | |
| // REGENERATE | |
| // ========================================== | |
| async function regenerate() { | |
| if (confirm('This will generate a new document list with the same answers. Continue?')) { | |
| await submitAnswers(); | |
| } | |
| } | |
| // ========================================== | |
| // KEYBOARD SHORTCUTS | |
| // ========================================== | |
| document.addEventListener('keydown', (e) => { | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| const activeSection = document.querySelector('.section.active'); | |
| if (activeSection && activeSection.id === 'questionPage') { | |
| const question = questions[currentQuestionIndex]; | |
| if (question.type === 'text' || question.type === 'number') { | |
| e.preventDefault(); | |
| nextQuestion(); | |
| } | |
| } | |
| } | |
| }); | |
| // ========================================== | |
| // INITIALIZE | |
| // ========================================== | |
| console.log('LegalDocs AI initialized'); | |
| console.log(`Total questions: ${questions.length}`); | |