您是否曾經發現很難理解一個雜亂的代碼庫?還是想知道分析和探索代碼的工具實際上是如何工作的?在本文中,我們將通過從頭開始構建強大的代碼庫探索工具來解決這些問題。使用靜態代碼分析和Gemini模型,我們將創建一個易於使用的系統,可幫助開發人員從其代碼中查詢,理解和獲得有用的見解。準備更改您導航代碼的方式了嗎?讓我們開始!
>本文是> > data Science Blogathon的一部分。 目錄的目錄
項目文件夾結構將類似於這些
在以下步驟中
設置項目環境:|--codebase_explorer/ |src/ ├──| __init__.py ├──| indexer/ │ ├── __init__.py │ └── code_parser.py ├──| query_engine/ │ ├── __init__.py │ ├── query_processor.py │ └── gemini_client.py | ├── main.py └── .env
#create a new conda env conda create -n cb_explorer python=3.11 conda activate cb_explorer
我們將從理解和實施代碼庫解析系統開始。它具有兩個重要的功能
pip install google-generativeai google-ai-generativelanguage pip install python-dotenv typer llama-index
extract_definitions()
>解析代碼庫
import ast import os from typing import Dict, Any def extract_definitions(tree: ast.AST) -> Dict[str, list]: """Extract class and function definitions from AST.""" definitions = { "classes": [], "functions": [], "imports": [] } for node in ast.walk(tree): if isinstance(node, ast.ClassDef): definitions["classes"].append({ "name": node.name, "lineno": node.lineno }) elif isinstance(node, ast.FunctionDef): definitions["functions"].append({ "name": node.name, "lineno": node.lineno }) elif isinstance(node, ast.Import): for name in node.names: definitions["imports"].append(name.name) return definitions
此功能掃描python文件的目錄,讀取其內容並提取其結構。
>
>它通過所有子目錄和給定目錄中的文件循環。import ast import os from typing import Dict, Any def parse_codebase(directory: str) -> Dict[str, Any]: """Parse Python files in the directory and extract code structure.""" code_structure = {} for root, _, files in os.walk(directory): for file in files: if file.endswith(".py"): file_path = os.path.join(root, file) with open(file_path, "r", encoding="utf-8") as f: try: content = f.read() tree = ast.parse(content) code_structure[file_path] = { "definitions": extract_definitions(tree), "content": content } except Exception as e: print(f"Error parsing {file_path}: {e}") return code_structure
提供了一種瀏覽整個目錄樹的遞歸方法。它將處理結束.py擴展的文件。
>使用Pythonast模塊將文件的內容解析到代表文件結構的抽象語法樹(AST)中。然後將提取的樹傳遞到extract_definitions(tree)。如果解析失敗,它將打印一條錯誤消息,但繼續處理其他文件。
的文件
gemini客戶端|--codebase_explorer/ |src/ ├──| __init__.py ├──| indexer/ │ ├── __init__.py │ └── code_parser.py ├──| query_engine/ │ ├── __init__.py │ ├── query_processor.py │ └── gemini_client.py | ├── main.py └── .env
類以與Google的Gemini AI模型進行交互。它將使用.ENV文件使用 google_api_key 來驗證模型。配置模型API後,它提供了一種查詢方法,可以在給定的提示符上生成響應。 >查詢處理系統
在本節中,我們將實現查詢過程類以管理代碼庫上下文並使用Gemini啟用查詢。加載必要的庫後,
load_dotenv#create a new conda env conda create -n cb_explorer python=3.11 conda activate cb_explorer
鍵。 > GEMINIEMBEDING類從Google服務器初始化嵌入式-001型號。 > QueryProcessor類旨在處理代碼庫上下文並與geminiclient.loading_contextmethod進行交互。 > thesaving_contextmethod將當前的代碼庫上下文保存到JSON文件中以供persistence.save_contextmethod更新代碼庫上下文,並立即將其保存為usingsave_context和theefformat_contextmetext和theeformat_contextMethod,將代碼庫數據轉換為可讀取人類的字符串形式,以徵求人類的字符串for for for for Human-munther-formaT for gromand formaties forman-fime >查詢雙子座是最重要的方法,它將使用代碼庫上下文和用戶的查詢構建提示。它通過GeminicLient將此提示發送到Gemini模型並恢復響應。 >命令行應用程序實現(CLI)
>在這裡,
|--codebase_explorer/ |src/ ├──| __init__.py ├──| indexer/ │ ├── __init__.py │ └── code_parser.py ├──| query_engine/ │ ├── __init__.py │ ├── query_processor.py │ └── gemini_client.py | ├── main.py └── .env
>它將首先檢查目錄是否存在,然後使用parse_codebase 函數在目錄中提取Python文件的結構。
解析後,它將保存在首先,檢查是否已加載了代碼庫上下文,並嘗試從計算機硬盤加載上下文。然後使用
query_processor的#create a new conda env conda create -n cb_explorer python=3.11 conda activate cb_explorer
和最後一個,它將使用typer.echo()方法。 步驟5:運行應用程序
測試應用程序
測試您的辛勤工作,請按照以下步驟進行操作:pip install google-generativeai google-ai-generativelanguage pip install python-dotenv typer llama-index
>在project_test文件夾中創建一個find_palidrome.py文件,然後將以下代碼放在文件中。
>import ast import os from typing import Dict, Any def extract_definitions(tree: ast.AST) -> Dict[str, list]: """Extract class and function definitions from AST.""" definitions = { "classes": [], "functions": [], "imports": [] } for node in ast.walk(tree): if isinstance(node, ast.ClassDef): definitions["classes"].append({ "name": node.name, "lineno": node.lineno }) elif isinstance(node, ast.FunctionDef): definitions["functions"].append({ "name": node.name, "lineno": node.lineno }) elif isinstance(node, ast.Import): for name in node.names: definitions["imports"].append(name.name) return definitions
>您可以顯示成功索引1 python文件。而且JSON數據看起來像
import ast import os from typing import Dict, Any def parse_codebase(directory: str) -> Dict[str, Any]: """Parse Python files in the directory and extract code structure.""" code_structure = {} for root, _, files in os.walk(directory): for file in files: if file.endswith(".py"): file_path = os.path.join(root, file) with open(file_path, "r", encoding="utf-8") as f: try: content = f.read() tree = ast.parse(content) code_structure[file_path] = { "definitions": extract_definitions(tree), "content": content } except Exception as e: print(f"Error parsing {file_path}: {e}") return code_structure
>查詢項目
import os from typing import Optional from google import generativeai as genai from dotenv import load_dotenv load_dotenv() class GeminiClient: def __init__(self): self.api_key = os.getenv("GOOGLE_API_KEY") if not self.api_key: raise ValueError("GOOGLE_API_KEY environment variable is not set") genai.configure(api_key=self.api_key) self.model = genai.GenerativeModel("gemini-1.5-flash") def query(self, prompt: str) -> Optional[str]: """Query Gemini with the given prompt.""" try: response = self.model.generate_content(prompt) return response.text except Exception as e: print(f"Error querying Gemini: {e}") return None
輸出:
import os import json from llama_index.embeddings.gemini import GeminiEmbedding from dotenv import load_dotenv from typing import Dict, Any, Optional from .gemini_client import GeminiClient load_dotenv() gemini_api_key = os.getenv("GOOGLE_API_KEY") model_name = "models/embeddings-001" embed_model = GeminiEmbedding(model_name=model_name, api_key=gemini_api_key) class QueryProcessor: def __init__(self): self.gemini_client = GeminiClient() self.codebase_context: Optional[Dict[str, Any]] = None self.index_file = "./indexes/codebase_index.json" def load_context(self): """Load the codebase context from disk if it exists.""" if os.path.exists(self.index_file): try: with open(self.index_file, "r", encoding="utf-8") as f: self.codebase_context = json.load(f) except Exception as e: print(f"Error loading index: {e}") self.codebase_context = None def save_context(self): """Save the codebase context to disk.""" if self.codebase_context: try: with open(self.index_file, "w", encoding="utf-8") as f: json.dump(self.codebase_context, f, indent=2) except Exception as e: print(f"Error saving index: {e}") def set_context(self, context: Dict[str, Any]): """Set the codebase context for queries.""" self.codebase_context = context self.save_context() def format_context(self) -> str: """Format the codebase context for Gemini.""" if not self.codebase_context: return "" context_parts = [] for file_path, details in self.codebase_context.items(): defs = details["definitions"] context_parts.append( f"File: {file_path}\n" f"Classes: {[c['name'] for c in defs['classes']]}\n" f"Functions: {[f['name'] for f in defs['functions']]}\n" f"Imports: {defs['imports']}\n" ) return "\n\n".join(context_parts) def query(self, query: str) -> Optional[str]: """Process a query about the codebase.""" if not self.codebase_context: return ( "Error: No codebase context available. Please index the codebase first." ) prompt = f""" Given the following codebase structure: {self.format_context()} Query: {query} Please provide a detailed and accurate answer based on the codebase structure above. """ return self.gemini_client.query(prompt)
import os import json import typer from pathlib import Path from typing import Optional from indexer.code_parser import parse_codebase from query_engine.query_processor import QueryProcessor
未來的發展 這是基礎系統的原型,可以通過許多有趣的功能進行擴展,例如
結構代碼解析是代碼分析的最重要的技術。
以上是使用Google' s gemini-2.0構建代碼庫資源管理器的詳細內容。更多資訊請關注PHP中文網其他相關文章!