| import os |
| import logging |
| from typing import Dict, List, Optional |
| from langchain_openai import ChatOpenAI |
| from pydantic import BaseModel, Field |
| from langchain_core.prompts import ChatPromptTemplate |
|
|
| |
| logger = logging.getLogger(__name__) |
|
|
| |
| class CodeFile(BaseModel): |
| filename: str = Field(description="Name of the file, e.g., 'NotificationFactory.java'") |
| content: str = Field(description="Complete source code for the file") |
| |
| class LLDCodeResponse(BaseModel): |
| title: str = Field(description="Title of the design pattern being demonstrated") |
| subtitle: str = Field(description="Subtitle explaining the specific implementation") |
| files: List[CodeFile] = Field(description="List of code files. Max 3-4 files.") |
| execution_output: str = Field(description="Console output for the Main execution file.") |
| typing_speed: int = Field(default=25, description="Typing animation speed in ms per char") |
| auto_run: bool = Field(default=True, description="Whether to auto-run the animation") |
|
|
| |
| PATTERN_GUIDANCE = { |
| "singleton": { |
| "description": "Ensures a class has only one instance and provides global access", |
| "files_needed": ["Singleton class", "Main/Demo class"], |
| "key_concepts": ["Private constructor", "Static instance", "Thread safety"], |
| "example_domain": "Database connection, Logger, Configuration manager" |
| }, |
| "factory": { |
| "description": "Creates objects without specifying exact class to create", |
| "files_needed": ["Product interface", "Concrete products", "Factory class", "Main/Demo"], |
| "key_concepts": ["Product interface", "Concrete implementations", "Factory method"], |
| "example_domain": "Notification system (Email, SMS, Push), Vehicle factory, Payment processors" |
| }, |
| "observer": { |
| "description": "Defines one-to-many dependency between objects", |
| "files_needed": ["Subject interface", "Observer interface", "Concrete subject", "Concrete observers", "Main/Demo"], |
| "key_concepts": ["Subject", "Observer", "Notify mechanism", "Subscription"], |
| "example_domain": "Event system, Stock price updates, News feed, Weather station" |
| }, |
| "strategy": { |
| "description": "Defines family of algorithms, encapsulates each, makes them interchangeable", |
| "files_needed": ["Strategy interface", "Concrete strategies", "Context class", "Main/Demo"], |
| "key_concepts": ["Strategy interface", "Concrete strategies", "Context switching"], |
| "example_domain": "Payment methods, Sorting algorithms, Compression methods, Route calculation" |
| }, |
| "builder": { |
| "description": "Separates construction of complex object from representation", |
| "files_needed": ["Product class", "Builder interface/class", "Concrete builder", "Director (optional)", "Main/Demo"], |
| "key_concepts": ["Step-by-step construction", "Fluent interface", "Immutable product"], |
| "example_domain": "Building complex objects (House, Pizza, Document), Query builder" |
| }, |
| "decorator": { |
| "description": "Attaches additional responsibilities to object dynamically", |
| "files_needed": ["Component interface", "Concrete component", "Decorator base", "Concrete decorators", "Main/Demo"], |
| "key_concepts": ["Component interface", "Wrapping", "Composition over inheritance"], |
| "example_domain": "Coffee with addons, Text formatting, Stream wrappers" |
| }, |
| "adapter": { |
| "description": "Converts interface of class into another interface clients expect", |
| "files_needed": ["Target interface", "Adaptee class", "Adapter class", "Main/Demo"], |
| "key_concepts": ["Target interface", "Adaptee", "Adapter wrapping"], |
| "example_domain": "Legacy system integration, Third-party API wrapper" |
| }, |
| "command": { |
| "description": "Encapsulates request as object, allowing parameterization", |
| "files_needed": ["Command interface", "Concrete commands", "Receiver", "Invoker", "Main/Demo"], |
| "key_concepts": ["Command interface", "Execute method", "Receiver", "Undo capability"], |
| "example_domain": "Text editor operations, Remote control, Transaction system" |
| }, |
| "design_pattern": { |
| "description": "Generic design pattern implementation", |
| "files_needed": ["Interface", "Implementation", "Main/Demo"], |
| "key_concepts": ["Clean code", "SOLID principles", "Best practices"], |
| "example_domain": "Based on topic context" |
| } |
| } |
|
|
| class LLDCodeGenerator: |
| """ |
| Generator for Low-Level Design code examples using LangChain for structured multi-file output. |
| """ |
| |
| def __init__(self, client=None): |
| api_key = os.getenv("OPENAI_API_KEY") |
| if not api_key and client and hasattr(client, "api_key"): |
| api_key = client.api_key |
| |
| self.llm = ChatOpenAI( |
| model="gpt-4o", |
| temperature=0.2, |
| api_key=api_key |
| ) |
| self.logger = logging.getLogger(__name__) |
| |
| def generate_lld_code_content( |
| self, |
| slide_config: Dict, |
| topic: str, |
| architecture_description: str |
| ) -> Dict: |
| """ |
| Generate multi-file LLD code examples with pattern-specific guidance. |
| """ |
| focus = slide_config.get('focus', 'Low-Level Design') |
| language = slide_config.get('language', 'java') |
| lld_pattern = slide_config.get('lld_pattern', 'design_pattern') |
| |
| self.logger.info(f"Generating LLD code for: {focus} in {language} using pattern: {lld_pattern}") |
| |
| |
| pattern_info = PATTERN_GUIDANCE.get(lld_pattern.lower(), PATTERN_GUIDANCE['design_pattern']) |
| |
| |
| class PromptInput(BaseModel): |
| language: str |
| topic: str |
| focus: str |
| lld_pattern: str |
| pattern_description: str |
| files_needed: str |
| key_concepts: str |
| example_domain: str |
| context: str |
| |
| |
| system_prompt = """You are an expert software architect creating clean, educational code examples for Low-Level Design patterns. |
| |
| Generate complete, working multi-file code that demonstrates design patterns and SOLID principles. |
| |
| CRITICAL REQUIREMENTS: |
| |
| 1. **Pattern Implementation**: |
| - Implement the EXACT pattern specified: {lld_pattern} |
| - Pattern description: {pattern_description} |
| - Required files: {files_needed} |
| - Key concepts to demonstrate: {key_concepts} |
| - Use domain context: {example_domain} |
| |
| 2. **Multiple Files** (3-4 files): |
| - Interface/Abstract class (if applicable) |
| - Concrete implementation classes (2-3 variants) |
| - Main/Demo class showing usage |
| - Each file should be focused and follow Single Responsibility Principle |
| |
| 3. **REAL-WORLD NAMING**: |
| - **NEVER** use generic names like `ConcreteProductA`, `Component1`, `Observer1`, `StrategyA` |
| - **ALWAYS** use domain-specific names based on the TOPIC ({topic}) and FOCUS ({focus}) |
| - Example for Notification System + Factory pattern: |
| ✓ GOOD: `NotificationFactory`, `EmailNotification`, `SMSNotification`, `PushNotification` |
| ✗ BAD: `Factory`, `ProductA`, `ProductB`, `ConcreteProduct1` |
| - Example for Payment System + Strategy pattern: |
| ✓ GOOD: `PaymentStrategy`, `CreditCardPayment`, `PayPalPayment`, `CryptoPayment` |
| ✗ BAD: `Strategy`, `ConcreteStrategyA`, `ConcreteStrategyB` |
| |
| 4. **Clean Code**: |
| - Use proper naming conventions for {language} |
| - Add helpful comments explaining pattern-specific parts |
| - COMPACT formatting: Use MINIMAL blank lines (max 1 blank line between methods/classes) |
| - NO excessive spacing or empty lines at start of files |
| - Keep code visually compact and professional |
| |
| 5. **Pattern-Specific Implementation**: |
| - For **Factory**: Show polymorphic object creation without exposing instantiation logic |
| - For **Singleton**: Include thread-safe implementation, private constructor, static instance |
| - For **Observer**: Demonstrate subject-observer relationship, notify mechanism |
| - For **Strategy**: Show algorithm family, context switching between strategies |
| - For **Builder**: Implement step-by-step construction, fluent interface |
| - For **Decorator**: Show component wrapping, responsibility addition |
| - For **Adapter**: Demonstrate interface conversion between incompatible interfaces |
| - For **Command**: Encapsulate requests as objects, show execute/undo |
| |
| 6. **Execution Output**: |
| - Provide realistic console output showing the pattern in action |
| - Output should demonstrate key pattern benefits |
| - Show object creation, method calls, state changes |
| |
| 7. **Language**: {language} |
| |
| OUTPUT STRUCTURE: |
| Return a JSON object with: |
| - title: Pattern name + brief description |
| - subtitle: Specific implementation focus |
| - files: list of objects {{filename, content}} |
| - execution_output: string containing the console output |
| - typing_speed: 25-35 (ms per character) |
| - auto_run: true |
| """ |
|
|
| user_prompt = """ |
| TOPIC: {topic} |
| FOCUS: {focus} |
| PATTERN: {lld_pattern} |
| PATTERN DESCRIPTION: {pattern_description} |
| KEY CONCEPTS: {key_concepts} |
| EXAMPLE DOMAIN: {example_domain} |
| CONTEXT: {context} |
| |
| Generate the complete pattern implementation now with proper domain-specific names. |
| """ |
| |
| try: |
| structured_llm = self.llm.with_structured_output(LLDCodeResponse) |
| prompt = ChatPromptTemplate.from_messages([ |
| ("system", system_prompt), |
| ("user", user_prompt) |
| ]) |
| |
| chain = prompt | structured_llm |
| |
| |
| prompt_input = PromptInput( |
| language=language, |
| topic=topic, |
| focus=focus, |
| lld_pattern=lld_pattern, |
| pattern_description=pattern_info['description'], |
| files_needed=", ".join(pattern_info['files_needed']), |
| key_concepts=", ".join(pattern_info['key_concepts']), |
| example_domain=pattern_info['example_domain'], |
| context=architecture_description[:800] |
| ) |
| |
| result: LLDCodeResponse = chain.invoke(prompt_input.model_dump()) |
| |
| |
| code_files_dict = {f.filename: f.content for f in result.files} |
| |
| |
| exec_output_dict = {name: "" for name in code_files_dict} |
| |
| |
| main_file = next( |
| (f for f in code_files_dict if "Main" in f or "Demo" in f or "App" in f or "Test" in f), |
| list(code_files_dict.keys())[-1] |
| ) |
| if main_file: |
| exec_output_dict[main_file] = result.execution_output |
| |
| self.logger.info(f"Generated {len(code_files_dict)} files for {lld_pattern} pattern") |
| |
| return { |
| "title": result.title, |
| "subtitle": result.subtitle, |
| "code_files": code_files_dict, |
| "execution_output": exec_output_dict, |
| "typing_speed": result.typing_speed, |
| "auto_run": result.auto_run, |
| "pattern": lld_pattern |
| } |
| |
| except Exception as e: |
| self.logger.error(f"Error generating LLD code with LangChain: {e}") |
| return self._get_fallback_lld_code(focus, language, lld_pattern) |
|
|
| def _get_fallback_lld_code(self, focus: str, language: str, pattern: str) -> Dict: |
| """Fallback LLD code if generation fails - pattern-specific""" |
| self.logger.warning(f"Using fallback LLD code for {pattern}") |
| |
| if pattern.lower() == "singleton": |
| return { |
| "title": "Singleton Pattern", |
| "subtitle": "Thread-Safe Database Connection", |
| "code_files": { |
| "DatabaseConnection.java": """public class DatabaseConnection { |
| private static volatile DatabaseConnection instance; |
| private String connectionString; |
| |
| private DatabaseConnection() { |
| // Private constructor |
| this.connectionString = "jdbc:mysql://localhost:3306/mydb"; |
| System.out.println("Database connection initialized"); |
| } |
| |
| public static DatabaseConnection getInstance() { |
| if (instance == null) { |
| synchronized (DatabaseConnection.class) { |
| if (instance == null) { |
| instance = new DatabaseConnection(); |
| } |
| } |
| } |
| return instance; |
| } |
| |
| public void query(String sql) { |
| System.out.println("Executing: " + sql); |
| } |
| }""", |
| "Main.java": """public class Main { |
| public static void main(String[] args) { |
| // Only one instance created |
| DatabaseConnection db1 = DatabaseConnection.getInstance(); |
| DatabaseConnection db2 = DatabaseConnection.getInstance(); |
| |
| System.out.println("Same instance? " + (db1 == db2)); |
| |
| db1.query("SELECT * FROM users"); |
| } |
| }""" |
| }, |
| "execution_output": { |
| "Main.java": """Database connection initialized |
| Same instance? true |
| Executing: SELECT * FROM users""" |
| }, |
| "typing_speed": 25, |
| "auto_run": True, |
| "pattern": "singleton" |
| } |
| |
| |
| return { |
| "title": focus, |
| "subtitle": "Fallback Example", |
| "code_files": { |
| "Main.java": f"""public class Main {{ |
| public static void main(String[] args) {{ |
| System.out.println("Error generating {pattern} pattern code."); |
| System.out.println("Focus: {focus}"); |
| }} |
| }}""" |
| }, |
| "execution_output": { |
| "Main.java": f"Error generating {pattern} pattern code.\nFocus: {focus}" |
| }, |
| "typing_speed": 25, |
| "auto_run": True, |
| "pattern": pattern |
| } |