1+ """
2+ Functions for ingesting repositories and sending context to OpenAI API.
3+ """
4+
5+ import httpx
6+ from typing import Optional , Dict , Any
7+ from dotenv import load_dotenv
8+ import os
9+ from gitingest import ingest_async
10+
11+ # Load environment variables from .env file
12+ load_dotenv ()
13+
14+
15+ async def use_gitingest (url : str , context_size : int = 50000 ) -> str :
16+ """
17+ Ingest a repository using gitingest and trim to specified token size.
18+
19+ Args:
20+ url: Repository URL to ingest
21+ context_size: Maximum context size in tokens (default ~50k tokens)
22+
23+ Returns:
24+ String containing the repository context, trimmed to specified size
25+ """
26+ # Ingest the repository
27+ summary , tree , content = await ingest_async (
28+ url ,
29+ max_file_size = 512000 ,
30+ include_patterns = None ,
31+ exclude_patterns = None
32+ )
33+
34+ # Combine into single context
35+ full_context = f"{ summary } \n \n { tree } \n \n { content } "
36+
37+ # Approximate token count (roughly 4 chars per token)
38+ # Trim to specified context size
39+ max_chars = context_size * 4
40+ if len (full_context ) > max_chars :
41+ full_context = full_context [:max_chars ]
42+ # Add ellipsis to indicate truncation
43+ full_context += "\n \n ... (context truncated)"
44+
45+ return full_context
46+
47+
48+ def smart_ingest (
49+ context : str ,
50+ user_prompt : str = "Analyze this repository and provide insights" ,
51+ api_key : Optional [str ] = None
52+ ) -> Dict [str , Any ]:
53+ """
54+ Send the ingested repository context to OpenAI API with a system prompt.
55+
56+ Args:
57+ context: The "big fat context" from use_git_ingest function
58+ user_prompt: The user's question or request about the repository
59+ api_key: Optional OpenAI API key (defaults to env var OPENAI_API_KEY)
60+
61+ Returns:
62+ Dictionary containing OpenAI's response and metadata
63+
64+ Raises:
65+ Exception: If the API call fails
66+ """
67+ # Get API key from environment if not provided
68+ if not api_key :
69+ api_key = os .getenv ("OPENAI_API_KEY" )
70+ if not api_key :
71+ raise ValueError ("OPENAI_API_KEY not found in environment variables" )
72+
73+ # System prompt for repository analysis
74+ system_prompt = """You are an expert code analyst and software architect.
75+ You have been given the complete context of a repository including its structure and file contents.
76+ Analyze the repository thoroughly and provide insights based on the user's request.
77+ Focus on:
78+ - Code quality and architecture
79+ - Potential improvements
80+ - Security considerations
81+ - Documentation completeness
82+ - Dependencies and technical debt
83+ Be specific and provide actionable recommendations."""
84+
85+ # Prepare messages for OpenAI
86+ messages = [
87+ {
88+ "role" : "system" ,
89+ "content" : system_prompt
90+ },
91+ {
92+ "role" : "user" ,
93+ "content" : f"{ user_prompt } \n \n { context } "
94+ }
95+ ]
96+
97+ # OpenAI API endpoint
98+ url = "https://api.openai.com/v1/chat/completions"
99+
100+ # Headers for the API request
101+ headers = {
102+ "Authorization" : f"Bearer { api_key } " ,
103+ "Content-Type" : "application/json"
104+ }
105+
106+ # Request body
107+ data = {
108+ "model" : "gpt-4o-mini" , # Using GPT-4o-mini for cost efficiency
109+ "messages" : messages ,
110+ "temperature" : 0.3 , # Lower temperature for more focused analysis
111+ "max_tokens" : 4096
112+ }
113+
114+ try :
115+ # Make the API call
116+ with httpx .Client (timeout = 60.0 ) as client :
117+ response = client .post (url , json = data , headers = headers )
118+ response .raise_for_status ()
119+
120+ result = response .json ()
121+
122+ # Extract the response
123+ choice = result .get ("choices" , [{}])[0 ]
124+ message = choice .get ("message" , {})
125+
126+ return {
127+ "success" : True ,
128+ "response" : message .get ("content" , "" ),
129+ "model" : result .get ("model" ),
130+ "usage" : result .get ("usage" , {}),
131+ "finish_reason" : choice .get ("finish_reason" )
132+ }
133+
134+ except httpx .HTTPStatusError as e :
135+ error_detail = e .response .text if e .response else str (e )
136+ raise Exception (f"OpenAI API error: { e .response .status_code } - { error_detail } " )
137+ except Exception as e :
138+ raise Exception (f"Failed to send context to OpenAI: { str (e )} " )
0 commit comments