Spaces:
Build error
Build error
| # Document Template Generation System for NAVADA | |
| """ | |
| Business document template generation with customizable formats | |
| for different startup stages and investor needs. | |
| """ | |
| import io | |
| import json | |
| import datetime | |
| from typing import Dict, Any, List, Optional | |
| from reportlab.lib.pagesizes import letter, A4 | |
| from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle | |
| from reportlab.lib.units import inch | |
| from reportlab.platypus import ( | |
| SimpleDocTemplate, Paragraph, Spacer, PageBreak, | |
| Table, TableStyle, Image, KeepTogether, ListFlowable, ListItem | |
| ) | |
| from reportlab.lib import colors | |
| from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT, TA_JUSTIFY | |
| from reportlab.pdfgen import canvas | |
| from reportlab.lib.utils import ImageReader | |
| import pandas as pd | |
| class DocumentTemplateGenerator: | |
| """Generate professional business documents for startups.""" | |
| def __init__(self): | |
| self.styles = self._create_custom_styles() | |
| self.templates = { | |
| 'business_case': self.generate_business_case, | |
| 'pitch_deck': self.generate_pitch_deck_outline, | |
| 'financial_model': self.generate_financial_model_template, | |
| 'investor_memo': self.generate_investor_memo, | |
| 'executive_summary': self.generate_executive_summary, | |
| 'market_analysis': self.generate_market_analysis, | |
| 'competitive_analysis': self.generate_competitive_analysis, | |
| 'go_to_market': self.generate_go_to_market_strategy, | |
| 'risk_assessment': self.generate_risk_assessment, | |
| 'term_sheet': self.generate_term_sheet_template | |
| } | |
| def _create_custom_styles(self): | |
| """Create custom paragraph styles for professional documents.""" | |
| styles = getSampleStyleSheet() | |
| # Title style | |
| styles.add(ParagraphStyle( | |
| name='CustomTitle', | |
| parent=styles['Title'], | |
| fontSize=24, | |
| textColor=colors.HexColor('#1a1a1a'), | |
| spaceAfter=30, | |
| alignment=TA_CENTER | |
| )) | |
| # Heading styles | |
| styles.add(ParagraphStyle( | |
| name='CustomHeading1', | |
| parent=styles['Heading1'], | |
| fontSize=18, | |
| textColor=colors.HexColor('#2c3e50'), | |
| spaceAfter=16, | |
| spaceBefore=12, | |
| leftIndent=0, | |
| fontName='Helvetica-Bold' | |
| )) | |
| styles.add(ParagraphStyle( | |
| name='CustomHeading2', | |
| parent=styles['Heading2'], | |
| fontSize=14, | |
| textColor=colors.HexColor('#34495e'), | |
| spaceAfter=12, | |
| spaceBefore=8, | |
| leftIndent=10, | |
| fontName='Helvetica-Bold' | |
| )) | |
| # Body text | |
| styles.add(ParagraphStyle( | |
| name='CustomBodyText', | |
| parent=styles['BodyText'], | |
| fontSize=11, | |
| textColor=colors.HexColor('#2c3e50'), | |
| alignment=TA_JUSTIFY, | |
| spaceAfter=12, | |
| leading=16 | |
| )) | |
| # Bullet points | |
| styles.add(ParagraphStyle( | |
| name='CustomBullet', | |
| parent=styles['BodyText'], | |
| fontSize=11, | |
| leftIndent=20, | |
| bulletIndent=10, | |
| spaceAfter=8 | |
| )) | |
| return styles | |
| def generate_business_case(self, startup_data: Dict[str, Any]) -> bytes: | |
| """Generate a comprehensive business case document.""" | |
| buffer = io.BytesIO() | |
| doc = SimpleDocTemplate( | |
| buffer, | |
| pagesize=A4, | |
| rightMargin=72, | |
| leftMargin=72, | |
| topMargin=72, | |
| bottomMargin=72 | |
| ) | |
| story = [] | |
| # Cover Page | |
| story.append(Paragraph( | |
| f"<b>BUSINESS CASE</b><br/><br/>{startup_data.get('company_name', 'Your Startup')}", | |
| self.styles['CustomTitle'] | |
| )) | |
| story.append(Spacer(1, 0.5*inch)) | |
| # Date | |
| story.append(Paragraph( | |
| f"Prepared: {datetime.datetime.now().strftime('%B %d, %Y')}", | |
| self.styles['Normal'] | |
| )) | |
| story.append(PageBreak()) | |
| # Executive Summary | |
| story.append(Paragraph("EXECUTIVE SUMMARY", self.styles['CustomHeading1'])) | |
| story.append(Paragraph( | |
| startup_data.get('executive_summary', | |
| 'This business case outlines the strategic rationale, market opportunity, ' | |
| 'and financial projections for our venture. We address a significant market ' | |
| 'gap with an innovative solution that delivers measurable value to our target customers.'), | |
| self.styles['CustomBodyText'] | |
| )) | |
| story.append(Spacer(1, 0.3*inch)) | |
| # Problem Statement | |
| story.append(Paragraph("1. PROBLEM STATEMENT", self.styles['CustomHeading1'])) | |
| story.append(Paragraph( | |
| startup_data.get('problem_statement', | |
| 'The market currently faces significant challenges that create opportunities ' | |
| 'for innovative solutions. Our research indicates substantial unmet needs ' | |
| 'in our target segment.'), | |
| self.styles['CustomBodyText'] | |
| )) | |
| # Market Pain Points | |
| pain_points = startup_data.get('pain_points', [ | |
| 'Inefficient current solutions', | |
| 'High costs for existing alternatives', | |
| 'Poor user experience', | |
| 'Lack of integration capabilities' | |
| ]) | |
| story.append(Paragraph("Key Pain Points:", self.styles['CustomHeading2'])) | |
| for point in pain_points: | |
| story.append(Paragraph(f"• {point}", self.styles['CustomBullet'])) | |
| story.append(Spacer(1, 0.3*inch)) | |
| # Proposed Solution | |
| story.append(Paragraph("2. PROPOSED SOLUTION", self.styles['CustomHeading1'])) | |
| story.append(Paragraph( | |
| startup_data.get('solution', | |
| 'Our solution leverages cutting-edge technology and deep market insights ' | |
| 'to deliver a superior alternative that addresses all identified pain points.'), | |
| self.styles['CustomBodyText'] | |
| )) | |
| # Value Proposition | |
| story.append(Paragraph("Value Proposition:", self.styles['CustomHeading2'])) | |
| value_props = startup_data.get('value_proposition', [ | |
| '10x improvement in efficiency', | |
| '50% cost reduction', | |
| 'Seamless user experience', | |
| 'Full integration with existing systems' | |
| ]) | |
| for prop in value_props: | |
| story.append(Paragraph(f"• {prop}", self.styles['CustomBullet'])) | |
| story.append(Spacer(1, 0.3*inch)) | |
| # Market Analysis | |
| story.append(Paragraph("3. MARKET ANALYSIS", self.styles['CustomHeading1'])) | |
| # Market Size Table | |
| market_data = [ | |
| ['Market Segment', 'TAM', 'SAM', 'SOM (Year 3)'], | |
| ['Primary Market', | |
| startup_data.get('tam', '$50B'), | |
| startup_data.get('sam', '$5B'), | |
| startup_data.get('som', '$100M')], | |
| ['Growth Rate', '15% CAGR', '20% CAGR', '50% YoY'], | |
| ] | |
| market_table = Table(market_data, colWidths=[2.5*inch, 1.5*inch, 1.5*inch, 1.5*inch]) | |
| market_table.setStyle(TableStyle([ | |
| ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#34495e')), | |
| ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), | |
| ('ALIGN', (0, 0), (-1, -1), 'CENTER'), | |
| ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), | |
| ('FONTSIZE', (0, 0), (-1, 0), 10), | |
| ('BOTTOMPADDING', (0, 0), (-1, 0), 12), | |
| ('BACKGROUND', (0, 1), (-1, -1), colors.HexColor('#ecf0f1')), | |
| ('GRID', (0, 0), (-1, -1), 1, colors.HexColor('#bdc3c7')) | |
| ])) | |
| story.append(market_table) | |
| story.append(Spacer(1, 0.3*inch)) | |
| # Financial Projections | |
| story.append(Paragraph("4. FINANCIAL PROJECTIONS", self.styles['CustomHeading1'])) | |
| financial_data = [ | |
| ['Metric', 'Year 1', 'Year 2', 'Year 3', 'Year 5'], | |
| ['Revenue', '$500K', '$2.5M', '$10M', '$50M'], | |
| ['Gross Margin', '60%', '65%', '70%', '75%'], | |
| ['EBITDA', '-$1M', '-$500K', '$2M', '$15M'], | |
| ['Cash Flow', '-$1.5M', '-$200K', '$1.5M', '$12M'], | |
| ] | |
| financial_table = Table(financial_data, colWidths=[1.8*inch, 1.2*inch, 1.2*inch, 1.2*inch, 1.2*inch]) | |
| financial_table.setStyle(TableStyle([ | |
| ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#27ae60')), | |
| ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), | |
| ('ALIGN', (0, 0), (-1, -1), 'CENTER'), | |
| ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), | |
| ('FONTSIZE', (0, 0), (-1, 0), 10), | |
| ('BOTTOMPADDING', (0, 0), (-1, 0), 12), | |
| ('BACKGROUND', (0, 1), (-1, -1), colors.HexColor('#e8f8f5')), | |
| ('GRID', (0, 0), (-1, -1), 1, colors.HexColor('#27ae60')) | |
| ])) | |
| story.append(financial_table) | |
| story.append(Spacer(1, 0.3*inch)) | |
| # Implementation Timeline | |
| story.append(Paragraph("5. IMPLEMENTATION TIMELINE", self.styles['CustomHeading1'])) | |
| phases = startup_data.get('timeline', [ | |
| {'phase': 'Phase 1: MVP Development', 'duration': '3 months', | |
| 'deliverables': 'Core product features, initial user testing'}, | |
| {'phase': 'Phase 2: Market Launch', 'duration': '2 months', | |
| 'deliverables': 'Go-to-market execution, first customers'}, | |
| {'phase': 'Phase 3: Scale', 'duration': '6 months', | |
| 'deliverables': 'Product refinement, team expansion, Series A'}, | |
| ]) | |
| for phase in phases: | |
| story.append(Paragraph(f"<b>{phase['phase']}</b> ({phase['duration']})", | |
| self.styles['CustomHeading2'])) | |
| story.append(Paragraph(f"Deliverables: {phase['deliverables']}", | |
| self.styles['CustomBodyText'])) | |
| story.append(Spacer(1, 0.3*inch)) | |
| # Risk Assessment | |
| story.append(Paragraph("6. RISK ASSESSMENT", self.styles['CustomHeading1'])) | |
| risks = startup_data.get('risks', [ | |
| {'risk': 'Market Risk', 'impact': 'High', 'mitigation': 'Extensive customer validation and pivoting capability'}, | |
| {'risk': 'Technical Risk', 'impact': 'Medium', 'mitigation': 'Experienced team and proven technology stack'}, | |
| {'risk': 'Competitive Risk', 'impact': 'Medium', 'mitigation': 'First-mover advantage and strong IP protection'}, | |
| {'risk': 'Financial Risk', 'impact': 'High', 'mitigation': 'Conservative burn rate and multiple funding sources'}, | |
| ]) | |
| risk_data = [['Risk Type', 'Impact', 'Mitigation Strategy']] | |
| for risk in risks: | |
| risk_data.append([risk['risk'], risk['impact'], risk['mitigation']]) | |
| risk_table = Table(risk_data, colWidths=[1.5*inch, 1*inch, 3.5*inch]) | |
| risk_table.setStyle(TableStyle([ | |
| ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#e74c3c')), | |
| ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), | |
| ('ALIGN', (0, 0), (-1, -1), 'LEFT'), | |
| ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), | |
| ('FONTSIZE', (0, 0), (-1, 0), 10), | |
| ('BOTTOMPADDING', (0, 0), (-1, 0), 12), | |
| ('BACKGROUND', (0, 1), (-1, -1), colors.HexColor('#fadbd8')), | |
| ('GRID', (0, 0), (-1, -1), 1, colors.HexColor('#e74c3c')) | |
| ])) | |
| story.append(risk_table) | |
| story.append(PageBreak()) | |
| # Investment Requirements | |
| story.append(Paragraph("7. INVESTMENT REQUIREMENTS", self.styles['CustomHeading1'])) | |
| funding_need = startup_data.get('funding_need', '$2M') | |
| use_of_funds = startup_data.get('use_of_funds', [ | |
| {'category': 'Product Development', 'allocation': '40%', 'amount': '$800K'}, | |
| {'category': 'Sales & Marketing', 'allocation': '30%', 'amount': '$600K'}, | |
| {'category': 'Operations', 'allocation': '20%', 'amount': '$400K'}, | |
| {'category': 'Reserve', 'allocation': '10%', 'amount': '$200K'}, | |
| ]) | |
| story.append(Paragraph( | |
| f"<b>Total Funding Required:</b> {funding_need}", | |
| self.styles['CustomBodyText'] | |
| )) | |
| story.append(Spacer(1, 0.2*inch)) | |
| story.append(Paragraph("Use of Funds:", self.styles['CustomHeading2'])) | |
| funds_data = [['Category', 'Allocation', 'Amount']] | |
| for fund in use_of_funds: | |
| funds_data.append([fund['category'], fund['allocation'], fund['amount']]) | |
| funds_table = Table(funds_data, colWidths=[2.5*inch, 1.5*inch, 1.5*inch]) | |
| funds_table.setStyle(TableStyle([ | |
| ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#3498db')), | |
| ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), | |
| ('ALIGN', (0, 0), (-1, -1), 'CENTER'), | |
| ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), | |
| ('FONTSIZE', (0, 0), (-1, 0), 10), | |
| ('BOTTOMPADDING', (0, 0), (-1, 0), 12), | |
| ('BACKGROUND', (0, 1), (-1, -1), colors.HexColor('#ebf5fb')), | |
| ('GRID', (0, 0), (-1, -1), 1, colors.HexColor('#3498db')) | |
| ])) | |
| story.append(funds_table) | |
| story.append(Spacer(1, 0.3*inch)) | |
| # Expected Returns | |
| story.append(Paragraph("Expected Returns:", self.styles['CustomHeading2'])) | |
| story.append(Paragraph( | |
| f"• Target IRR: {startup_data.get('target_irr', '35%')}<br/>" | |
| f"• Exit Timeline: {startup_data.get('exit_timeline', '5-7 years')}<br/>" | |
| f"• Exit Multiple: {startup_data.get('exit_multiple', '10x')}<br/>", | |
| self.styles['CustomBodyText'] | |
| )) | |
| # Conclusion | |
| story.append(Paragraph("8. CONCLUSION", self.styles['CustomHeading1'])) | |
| story.append(Paragraph( | |
| startup_data.get('conclusion', | |
| 'This business case demonstrates a compelling opportunity with strong ' | |
| 'fundamentals, clear market demand, and a capable team. The financial ' | |
| 'projections show a path to profitability and significant returns for investors. ' | |
| 'We are positioned to capture a meaningful share of a large and growing market.'), | |
| self.styles['CustomBodyText'] | |
| )) | |
| # Next Steps | |
| story.append(Paragraph("Next Steps:", self.styles['CustomHeading2'])) | |
| next_steps = startup_data.get('next_steps', [ | |
| 'Finalize investment terms', | |
| 'Complete due diligence process', | |
| 'Execute growth strategy', | |
| 'Achieve key milestones' | |
| ]) | |
| for step in next_steps: | |
| story.append(Paragraph(f"• {step}", self.styles['CustomBullet'])) | |
| # Build PDF | |
| doc.build(story) | |
| buffer.seek(0) | |
| return buffer.getvalue() | |
| def generate_pitch_deck_outline(self, startup_data: Dict[str, Any]) -> bytes: | |
| """Generate a pitch deck outline document.""" | |
| buffer = io.BytesIO() | |
| doc = SimpleDocTemplate(buffer, pagesize=letter) | |
| story = [] | |
| # Title | |
| story.append(Paragraph( | |
| f"<b>PITCH DECK OUTLINE</b><br/><br/>{startup_data.get('company_name', 'Your Startup')}", | |
| self.styles['CustomTitle'] | |
| )) | |
| story.append(PageBreak()) | |
| # Slide structure | |
| slides = [ | |
| { | |
| 'number': '1', | |
| 'title': 'Title Slide', | |
| 'content': [ | |
| 'Company name and logo', | |
| 'Tagline/Value proposition', | |
| 'Contact information' | |
| ], | |
| 'tips': 'Keep it clean and professional. First impressions matter.' | |
| }, | |
| { | |
| 'number': '2', | |
| 'title': 'Problem', | |
| 'content': [ | |
| 'Clear problem statement', | |
| 'Who experiences this problem', | |
| 'Current solutions and their shortcomings', | |
| 'Market pain points' | |
| ], | |
| 'tips': 'Make it relatable. Use real examples and stories.' | |
| }, | |
| { | |
| 'number': '3', | |
| 'title': 'Solution', | |
| 'content': [ | |
| 'Your unique solution', | |
| 'Key features and benefits', | |
| 'Product demo or screenshots', | |
| 'Technology advantage' | |
| ], | |
| 'tips': 'Show, don\'t just tell. Use visuals and demos when possible.' | |
| }, | |
| { | |
| 'number': '4', | |
| 'title': 'Market Opportunity', | |
| 'content': [ | |
| 'TAM, SAM, SOM analysis', | |
| 'Market growth trends', | |
| 'Target customer segments', | |
| 'Geographic expansion potential' | |
| ], | |
| 'tips': 'Use credible sources. Show bottom-up market sizing.' | |
| }, | |
| { | |
| 'number': '5', | |
| 'title': 'Business Model', | |
| 'content': [ | |
| 'Revenue streams', | |
| 'Pricing strategy', | |
| 'Customer acquisition cost (CAC)', | |
| 'Lifetime value (LTV)', | |
| 'Unit economics' | |
| ], | |
| 'tips': 'Be specific about how you make money. Show proven metrics if available.' | |
| }, | |
| { | |
| 'number': '6', | |
| 'title': 'Traction', | |
| 'content': [ | |
| 'Key metrics and KPIs', | |
| 'Customer testimonials', | |
| 'Revenue growth', | |
| 'User growth', | |
| 'Partnerships' | |
| ], | |
| 'tips': 'Use charts and graphs. Show month-over-month growth.' | |
| }, | |
| { | |
| 'number': '7', | |
| 'title': 'Competition', | |
| 'content': [ | |
| 'Competitive landscape', | |
| 'Your unique advantages', | |
| 'Barriers to entry', | |
| 'Positioning matrix' | |
| ], | |
| 'tips': 'Be honest about competition. Show why you\'ll win.' | |
| }, | |
| { | |
| 'number': '8', | |
| 'title': 'Go-to-Market Strategy', | |
| 'content': [ | |
| 'Customer acquisition channels', | |
| 'Sales strategy', | |
| 'Marketing plan', | |
| 'Partnership strategy' | |
| ], | |
| 'tips': 'Show you understand your customers and how to reach them.' | |
| }, | |
| { | |
| 'number': '9', | |
| 'title': 'Team', | |
| 'content': [ | |
| 'Founder backgrounds', | |
| 'Key team members', | |
| 'Advisory board', | |
| 'Key investors' | |
| ], | |
| 'tips': 'Highlight relevant experience and past successes.' | |
| }, | |
| { | |
| 'number': '10', | |
| 'title': 'Financial Projections', | |
| 'content': [ | |
| '3-5 year revenue projections', | |
| 'Path to profitability', | |
| 'Key assumptions', | |
| 'Burn rate and runway' | |
| ], | |
| 'tips': 'Be realistic but ambitious. Show key drivers of growth.' | |
| }, | |
| { | |
| 'number': '11', | |
| 'title': 'The Ask', | |
| 'content': [ | |
| 'Funding amount', | |
| 'Use of funds', | |
| 'Milestones to be achieved', | |
| 'Expected timeline' | |
| ], | |
| 'tips': 'Be specific about what you need and what you\'ll accomplish.' | |
| }, | |
| { | |
| 'number': '12', | |
| 'title': 'Contact/Q&A', | |
| 'content': [ | |
| 'Contact details', | |
| 'Website and social media', | |
| 'Next steps', | |
| 'Q&A prompt' | |
| ], | |
| 'tips': 'End with a clear call to action.' | |
| } | |
| ] | |
| for slide in slides: | |
| story.append(Paragraph( | |
| f"<b>Slide {slide['number']}: {slide['title']}</b>", | |
| self.styles['CustomHeading1'] | |
| )) | |
| story.append(Paragraph("Content:", self.styles['CustomHeading2'])) | |
| for item in slide['content']: | |
| story.append(Paragraph(f"• {item}", self.styles['CustomBullet'])) | |
| story.append(Paragraph("💡 Tips:", self.styles['CustomHeading2'])) | |
| story.append(Paragraph(slide['tips'], self.styles['CustomBodyText'])) | |
| story.append(Spacer(1, 0.3*inch)) | |
| # Build PDF | |
| doc.build(story) | |
| buffer.seek(0) | |
| return buffer.getvalue() | |
| def generate_financial_model_template(self, startup_data: Dict[str, Any]) -> bytes: | |
| """Generate a financial model template document.""" | |
| buffer = io.BytesIO() | |
| doc = SimpleDocTemplate(buffer, pagesize=A4) | |
| story = [] | |
| # Title | |
| story.append(Paragraph( | |
| f"<b>FINANCIAL MODEL TEMPLATE</b><br/><br/>{startup_data.get('company_name', 'Your Startup')}", | |
| self.styles['CustomTitle'] | |
| )) | |
| story.append(PageBreak()) | |
| # Revenue Model | |
| story.append(Paragraph("REVENUE MODEL", self.styles['CustomHeading1'])) | |
| # Add revenue assumptions table | |
| revenue_assumptions = [ | |
| ['Parameter', 'Year 1', 'Year 2', 'Year 3', 'Notes'], | |
| ['Customer Acquisition', '100', '500', '2000', 'Based on marketing spend'], | |
| ['Avg. Revenue/Customer', '$500', '$600', '$750', 'Price increases with value'], | |
| ['Churn Rate', '10%', '8%', '5%', 'Improving retention'], | |
| ['Upsell Rate', '20%', '30%', '40%', 'Product expansion'] | |
| ] | |
| revenue_table = Table(revenue_assumptions) | |
| revenue_table.setStyle(TableStyle([ | |
| ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#2ecc71')), | |
| ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), | |
| ('ALIGN', (0, 0), (-1, -1), 'CENTER'), | |
| ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), | |
| ('FONTSIZE', (0, 0), (-1, 0), 10), | |
| ('GRID', (0, 0), (-1, -1), 1, colors.grey) | |
| ])) | |
| story.append(revenue_table) | |
| story.append(Spacer(1, 0.3*inch)) | |
| # Cost Structure | |
| story.append(Paragraph("COST STRUCTURE", self.styles['CustomHeading1'])) | |
| cost_structure = [ | |
| ['Cost Category', 'Year 1', 'Year 2', 'Year 3', '% of Revenue'], | |
| ['Personnel', '$500K', '$1.5M', '$3M', '30-40%'], | |
| ['Marketing', '$200K', '$750K', '$2M', '20-25%'], | |
| ['Technology', '$150K', '$300K', '$500K', '5-10%'], | |
| ['Operations', '$100K', '$250K', '$500K', '5-10%'], | |
| ['G&A', '$50K', '$200K', '$500K', '5%'] | |
| ] | |
| cost_table = Table(cost_structure) | |
| cost_table.setStyle(TableStyle([ | |
| ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#e74c3c')), | |
| ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), | |
| ('ALIGN', (0, 0), (-1, -1), 'CENTER'), | |
| ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), | |
| ('FONTSIZE', (0, 0), (-1, 0), 10), | |
| ('GRID', (0, 0), (-1, -1), 1, colors.grey) | |
| ])) | |
| story.append(cost_table) | |
| # Build PDF | |
| doc.build(story) | |
| buffer.seek(0) | |
| return buffer.getvalue() | |
| def generate_investor_memo(self, startup_data: Dict[str, Any]) -> bytes: | |
| """Generate an investor memorandum.""" | |
| buffer = io.BytesIO() | |
| doc = SimpleDocTemplate(buffer, pagesize=letter) | |
| story = [] | |
| # Title Page | |
| story.append(Paragraph( | |
| "<b>INVESTMENT MEMORANDUM</b>", | |
| self.styles['CustomTitle'] | |
| )) | |
| story.append(Spacer(1, 0.3*inch)) | |
| story.append(Paragraph( | |
| f"{startup_data.get('company_name', 'Your Startup')}", | |
| self.styles['CustomTitle'] | |
| )) | |
| story.append(Spacer(1, 0.5*inch)) | |
| story.append(Paragraph( | |
| "CONFIDENTIAL - NOT FOR DISTRIBUTION", | |
| self.styles['Normal'] | |
| )) | |
| story.append(Paragraph( | |
| f"Prepared: {datetime.datetime.now().strftime('%B %Y')}", | |
| self.styles['Normal'] | |
| )) | |
| story.append(PageBreak()) | |
| # Investment Highlights | |
| story.append(Paragraph("INVESTMENT HIGHLIGHTS", self.styles['CustomHeading1'])) | |
| highlights = startup_data.get('highlights', [ | |
| 'Large and growing addressable market ($50B+ TAM)', | |
| 'Proven business model with strong unit economics', | |
| 'Experienced team with relevant domain expertise', | |
| 'Clear path to profitability within 24 months', | |
| 'Strategic partnerships with industry leaders', | |
| 'Proprietary technology with defensible moat' | |
| ]) | |
| for highlight in highlights: | |
| story.append(Paragraph(f"✓ {highlight}", self.styles['CustomBullet'])) | |
| story.append(Spacer(1, 0.3*inch)) | |
| # Investment Terms | |
| story.append(Paragraph("INVESTMENT TERMS", self.styles['CustomHeading1'])) | |
| terms_data = [ | |
| ['Parameter', 'Terms'], | |
| ['Round Type', startup_data.get('round_type', 'Series A')], | |
| ['Target Raise', startup_data.get('target_raise', '$10M')], | |
| ['Pre-Money Valuation', startup_data.get('pre_money', '$40M')], | |
| ['Minimum Investment', startup_data.get('minimum', '$250K')], | |
| ['Use of Funds', 'Product (40%), Sales (30%), Ops (20%), Reserve (10%)'], | |
| ['Expected Close', startup_data.get('close_date', 'Q2 2024')] | |
| ] | |
| terms_table = Table(terms_data, colWidths=[2*inch, 4*inch]) | |
| terms_table.setStyle(TableStyle([ | |
| ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#3498db')), | |
| ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), | |
| ('ALIGN', (0, 0), (-1, -1), 'LEFT'), | |
| ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), | |
| ('GRID', (0, 0), (-1, -1), 1, colors.grey) | |
| ])) | |
| story.append(terms_table) | |
| # Build PDF | |
| doc.build(story) | |
| buffer.seek(0) | |
| return buffer.getvalue() | |
| def generate_executive_summary(self, startup_data: Dict[str, Any]) -> bytes: | |
| """Generate an executive summary document.""" | |
| buffer = io.BytesIO() | |
| doc = SimpleDocTemplate(buffer, pagesize=letter) | |
| story = [] | |
| # Header | |
| story.append(Paragraph( | |
| f"<b>EXECUTIVE SUMMARY</b><br/><br/>{startup_data.get('company_name', 'Your Startup')}", | |
| self.styles['CustomTitle'] | |
| )) | |
| story.append(Spacer(1, 0.5*inch)) | |
| # Company Overview | |
| story.append(Paragraph("Company Overview", self.styles['CustomHeading1'])) | |
| story.append(Paragraph( | |
| startup_data.get('overview', | |
| 'We are building the next generation platform that transforms how businesses ' | |
| 'operate in the digital economy. Our solution addresses critical pain points ' | |
| 'with innovative technology and a customer-centric approach.'), | |
| self.styles['CustomBodyText'] | |
| )) | |
| story.append(Spacer(1, 0.2*inch)) | |
| # Mission & Vision | |
| story.append(Paragraph("Mission & Vision", self.styles['CustomHeading1'])) | |
| story.append(Paragraph( | |
| f"<b>Mission:</b> {startup_data.get('mission', 'To democratize access to advanced technology solutions')}", | |
| self.styles['CustomBodyText'] | |
| )) | |
| story.append(Paragraph( | |
| f"<b>Vision:</b> {startup_data.get('vision', 'To become the global leader in our category by 2030')}", | |
| self.styles['CustomBodyText'] | |
| )) | |
| story.append(Spacer(1, 0.2*inch)) | |
| # Key Metrics | |
| story.append(Paragraph("Key Metrics", self.styles['CustomHeading1'])) | |
| metrics = [ | |
| ['Metric', 'Current', 'Target (12mo)'], | |
| ['ARR', '$2M', '$10M'], | |
| ['Customers', '50', '200'], | |
| ['NPS Score', '72', '80+'], | |
| ['Gross Margin', '65%', '75%'] | |
| ] | |
| metrics_table = Table(metrics) | |
| metrics_table.setStyle(TableStyle([ | |
| ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#27ae60')), | |
| ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), | |
| ('ALIGN', (0, 0), (-1, -1), 'CENTER'), | |
| ('GRID', (0, 0), (-1, -1), 1, colors.grey) | |
| ])) | |
| story.append(metrics_table) | |
| # Build PDF | |
| doc.build(story) | |
| buffer.seek(0) | |
| return buffer.getvalue() | |
| def generate_market_analysis(self, startup_data: Dict[str, Any]) -> bytes: | |
| """Generate a market analysis report.""" | |
| # Implementation similar to above templates | |
| pass | |
| def generate_competitive_analysis(self, startup_data: Dict[str, Any]) -> bytes: | |
| """Generate a competitive analysis document.""" | |
| # Implementation similar to above templates | |
| pass | |
| def generate_go_to_market_strategy(self, startup_data: Dict[str, Any]) -> bytes: | |
| """Generate a go-to-market strategy document.""" | |
| # Implementation similar to above templates | |
| pass | |
| def generate_risk_assessment(self, startup_data: Dict[str, Any]) -> bytes: | |
| """Generate a risk assessment document.""" | |
| # Implementation similar to above templates | |
| pass | |
| def generate_term_sheet_template(self, startup_data: Dict[str, Any]) -> bytes: | |
| """Generate a term sheet template.""" | |
| buffer = io.BytesIO() | |
| doc = SimpleDocTemplate(buffer, pagesize=letter) | |
| story = [] | |
| # Title | |
| story.append(Paragraph( | |
| "<b>TERM SHEET</b>", | |
| self.styles['CustomTitle'] | |
| )) | |
| story.append(Spacer(1, 0.2*inch)) | |
| story.append(Paragraph( | |
| f"{startup_data.get('company_name', 'Your Startup, Inc.')}", | |
| self.styles['CustomTitle'] | |
| )) | |
| story.append(Spacer(1, 0.3*inch)) | |
| story.append(Paragraph( | |
| f"Series {startup_data.get('series', 'A')} Preferred Stock Financing", | |
| self.styles['Normal'] | |
| )) | |
| story.append(Spacer(1, 0.5*inch)) | |
| # Terms | |
| terms = [ | |
| ('Issuer', startup_data.get('company_name', 'Company, Inc.')), | |
| ('Investors', startup_data.get('lead_investor', 'Lead Investor') + ' and other investors'), | |
| ('Amount Raised', startup_data.get('amount', '$10,000,000')), | |
| ('Pre-Money Valuation', startup_data.get('pre_money', '$40,000,000')), | |
| ('Post-Money Valuation', startup_data.get('post_money', '$50,000,000')), | |
| ('Price Per Share', startup_data.get('price_per_share', '$1.00')), | |
| ('Liquidation Preference', '1x non-participating'), | |
| ('Dividend', '8% cumulative dividend'), | |
| ('Anti-Dilution', 'Weighted average broad-based'), | |
| ('Voting Rights', '1 vote per share, vote together with common'), | |
| ('Board Composition', '5 members: 2 founders, 2 investors, 1 independent'), | |
| ('Protective Provisions', 'Standard Series A provisions'), | |
| ('Registration Rights', 'Standard demand and piggyback rights'), | |
| ('Right of First Refusal', 'Company and investors'), | |
| ('Drag Along', 'Standard drag along provisions'), | |
| ('Vesting', 'Founders: 4 years with 1-year cliff'), | |
| ('Employee Pool', '15% post-financing'), | |
| ('Closing', startup_data.get('closing', '30 days from signing')) | |
| ] | |
| for term, value in terms: | |
| story.append(Paragraph( | |
| f"<b>{term}:</b> {value}", | |
| self.styles['CustomBodyText'] | |
| )) | |
| story.append(Spacer(1, 0.1*inch)) | |
| # Legal Notice | |
| story.append(Spacer(1, 0.5*inch)) | |
| story.append(Paragraph( | |
| "This term sheet is non-binding except for confidentiality, exclusivity, and governing law provisions.", | |
| self.styles['Italic'] | |
| )) | |
| # Build PDF | |
| doc.build(story) | |
| buffer.seek(0) | |
| return buffer.getvalue() | |
| def list_available_templates(self) -> List[str]: | |
| """Return list of available document templates.""" | |
| return list(self.templates.keys()) | |
| def generate_document(self, template_type: str, startup_data: Dict[str, Any]) -> bytes: | |
| """Generate a document based on the specified template type.""" | |
| if template_type not in self.templates: | |
| raise ValueError(f"Unknown template type: {template_type}") | |
| return self.templates[template_type](startup_data) | |
| # Export the class | |
| __all__ = ['DocumentTemplateGenerator'] |