Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Full Project Implementation

Section Goal: Integrate the components from previous sections to build an interactive AI coding assistant.

Complete AI Coding Assistant Component Integration Architecture


Integrating All Components

"""
Complete AI Coding Assistant
Integrates: code indexing + semantic search + code generation + test generation + bug fixing
"""
import asyncio
import os
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

# Import components implemented in previous sections (import from modules in real projects)
# Full implementations of each component are in the corresponding sections:
# from code_indexer import CodeIndexer         # → Section 19.2
# from code_search import CodeSearchEngine     # → Section 19.2
# from code_generator import CodeGenerator     # → Section 19.3
# from test_generator import TestGenerator     # → Section 19.4
# from bug_fixer import BugFixer               # → Section 19.4
# Note: Before running this section's code, save sections 19.2–19.4 code as independent modules

class AICodeAssistant:
    """AI Coding Assistant — complete implementation"""
    
    def __init__(self, project_path: str):
        self.project_path = project_path
        self.llm = ChatOpenAI(model="gpt-4o", temperature=0)
        self.embeddings = OpenAIEmbeddings()
        
        # Initialize components
        self.indexer = CodeIndexer(project_path)
        entities = self.indexer.build_index()
        
        self.searcher = CodeSearchEngine(entities, self.embeddings)
        self.searcher.build()
        
        self.generator = CodeGenerator(self.llm)
        self.test_gen = TestGenerator(self.llm)
        self.bug_fixer = BugFixer(self.llm)
        
        print(f"✅ Indexed {len(entities)} code entities")
    
    async def chat(self, user_input: str) -> str:
        """Handle user input"""
        
        # Identify intent
        intent = await self._classify_intent(user_input)
        
        if intent == "explain":
            return await self._handle_explain(user_input)
        elif intent == "generate":
            result = await self.generator.generate(user_input)
            return f"```python\n{result.code}\n```\n\n{result.explanation}"
        elif intent == "fix":
            return await self._handle_fix(user_input)
        elif intent == "test":
            return await self._handle_test(user_input)
        elif intent == "search":
            return await self._handle_search(user_input)
        else:
            return await self._handle_general(user_input)
    
    async def _classify_intent(self, user_input: str) -> str:
        """Classify user intent"""
        prompt = f"""Determine the user's intent, reply with only one word:
- explain: explain code
- generate: generate new code
- fix: fix a bug
- test: generate tests
- search: search code
- general: other questions

User said: {user_input}"""
        
        response = await self.llm.ainvoke(prompt)
        return response.content.strip().lower()
    
    async def _handle_explain(self, query: str) -> str:
        """Handle code explanation requests"""
        results = self.searcher.search(query, top_k=3)
        
        if not results:
            return "No relevant code found."
        
        context = "\n\n".join(
            f"**{e.file_path}** - `{e.name}`\n```python\n{e.source}\n```"
            for e in results
        )
        
        prompt = f"Explain the following code in plain language:\n\n{context}\n\nUser question: {query}"
        response = await self.llm.ainvoke(prompt)
        return response.content
    
    async def _handle_search(self, query: str) -> str:
        """Handle code search requests"""
        results = self.searcher.search(query, top_k=5)
        
        output = "🔍 Search results:\n\n"
        for i, entity in enumerate(results, 1):
            output += (
                f"{i}. **{entity.name}** ({entity.entity_type})\n"
                f"   📄 {entity.file_path}:L{entity.start_line}\n"
                f"   📝 {entity.docstring[:100] if entity.docstring else 'No documentation'}\n\n"
            )
        
        return output
    
    async def _handle_fix(self, query: str) -> str:
        """Handle bug fix requests"""
        # Search for potentially relevant code
        results = self.searcher.search(query, top_k=3)
        
        if results:
            code = results[0].source
            fix = await self.bug_fixer.diagnose_and_fix(
                code=code,
                error_message=query,
                file_path=results[0].file_path
            )
            return (
                f"🔍 **Cause**: {fix.get('root_cause', 'Unknown')}\n\n"
                f"🔧 **Fix**: {fix.get('fix_description', '')}\n\n"
                f"```python\n{fix.get('fixed_code', code)}\n```"
            )
        
        return "Please provide specific error information and the relevant file path."
    
    async def _handle_test(self, query: str) -> str:
        """Handle test generation requests"""
        results = self.searcher.search(query, top_k=1)
        
        if results:
            entity = results[0]
            tests = await self.test_gen.generate_tests(
                source_code=entity.source,
                file_path=entity.file_path
            )
            return f"Generated tests for `{entity.file_path}`:\n\n{tests}"
        
        return "Please specify the file or function to generate tests for."
    
    async def _handle_general(self, query: str) -> str:
        """Handle general questions"""
        prompt = f"""You are a professional coding assistant. Current project path: {self.project_path}
        
User question: {query}

Please answer with programming knowledge as much as possible."""
        
        response = await self.llm.ainvoke(prompt)
        return response.content


async def main():
    """Interactive main loop"""
    import sys
    
    project_path = sys.argv[1] if len(sys.argv) > 1 else "."
    
    print("🤖 AI Coding Assistant")
    print(f"📁 Project: {os.path.abspath(project_path)}")
    print("=" * 50)
    print("Type 'quit' to exit\n")
    
    assistant = AICodeAssistant(project_path)
    
    while True:
        user_input = input("You: ").strip()
        
        if user_input.lower() in ('quit', 'exit', 'q'):
            print("👋 Goodbye!")
            break
        
        if not user_input:
            continue
        
        response = await assistant.chat(user_input)
        print(f"\n🤖: {response}\n")


if __name__ == "__main__":
    asyncio.run(main())

Example Output

🤖 AI Coding Assistant
📁 Project: /home/user/my-project
==================================================
✅ Indexed 156 code entities
Type 'quit' to exit

You: Search all functions that handle user authentication
🤖: 🔍 Search results:
1. **authenticate_user** (function)
   📄 auth/service.py:L23
   📝 Verify user credentials and return JWT token

2. **verify_token** (function)
   📄 auth/middleware.py:L15
   📝 Verify JWT token in request

You: Explain the logic of authenticate_user
🤖: The `authenticate_user` function performs the following steps...

You: Generate tests for verify_token
🤖: Generated tests for `auth/middleware.py`:
    ...pytest test code...

Summary

FeatureImplementation
Code searchVector embeddings + cosine similarity
Code understandingAST analysis + LLM explanation
Code generationStructured output + quality validation
Test generationLLM generates pytest tests
Bug fixingError analysis + code fix

🎓 Chapter Summary: We built an AI coding assistant from scratch that can understand code, search code, generate code, write tests, and fix bugs. While this is a simplified version, it demonstrates the core ideas for building such tools.


Next Chapter: Chapter 20 Project Practice: Intelligent Data Analysis Agent →