Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions github.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def _fetch_github_api(api_url, params=None):
raise ValueError("Cached data is empty")
return 200, cached_data
except Exception as e:
print(f"⚠️ Warning: Error reading cache file {cache_filename}: {e}")
print(f"[WARNING] Error reading cache file {cache_filename}: {e}")
try:
os.remove(cache_filename)
except Exception as delete_err:
Expand Down Expand Up @@ -77,26 +77,26 @@ def _fetch_github_api(api_url, params=None):
max_wait = 3600
if wait_seconds > max_wait:
print(
f"⚠️ Rate limit reset time is too far in the future ({wait_seconds}s). Capping wait to {max_wait}s"
f"[WARNING] Rate limit reset time is too far in the future ({wait_seconds}s). Capping wait to {max_wait}s"
)
wait_seconds = max_wait

logger.error(
f"⚠️ GitHub API rate limit low: {remaining}/{limit} requests remaining. Resets at {reset_time}"
f"[WARNING] GitHub API rate limit low: {remaining}/{limit} requests remaining. Resets at {reset_time}"
)
print(
f"💡 Tip: Set GITHUB_TOKEN environment variable to increase rate limits (60/hour → 5000/hour)"
f"Tip: Set GITHUB_TOKEN environment variable to increase rate limits (60/hour → 5000/hour)"
)

if wait_seconds > 0:
logger.info(
f"Proactively sleeping for {wait_seconds} seconds until rate limit resets..."
f"Proactively sleeping for {wait_seconds} seconds until rate limit resets..."
)
time.sleep(wait_seconds)
print(f"Rate limit should be reset now. Continuing...")
print(f"Rate limit should be reset now. Continuing...")
elif remaining < 100:
logger.info(
f"ℹ️ GitHub API rate limit: {remaining}/{limit} requests remaining"
f"GitHub API rate limit: {remaining}/{limit} requests remaining"
)

data = response.json() if response.status_code == 200 else {}
Expand Down Expand Up @@ -286,9 +286,9 @@ def fetch_all_github_repos(github_url: str, max_repos: int = 100) -> List[Dict]:
1 for p in projects if p["project_type"] == "self_project"
)

print(f"Found {len(projects)} repositories")
print(f"Found {len(projects)} repositories")
print(
f"📊 Project classification: {open_source_count} open source, {self_project_count} self projects"
f"Project classification: {open_source_count} open source, {self_project_count} self projects"
)
return projects

Expand Down Expand Up @@ -363,7 +363,7 @@ def generate_projects_json(projects: List[Dict]) -> List[Dict]:
)

print(
f"🤖 Using LLM to select top 5 projects from {len(projects)} repositories..."
f"Using LLM to select top 5 projects from {len(projects)} repositories..."
)

# Initialize the LLM provider
Expand Down Expand Up @@ -409,7 +409,7 @@ def generate_projects_json(projects: List[Dict]) -> List[Dict]:

if len(unique_projects) < 7:
print(
f"⚠️ LLM selected {len(selected_projects)} projects but {len(unique_projects)} are unique"
f"[WARNING] LLM selected {len(selected_projects)} projects but {len(unique_projects)} are unique"
)

for project in projects_data:
Expand All @@ -424,20 +424,20 @@ def generate_projects_json(projects: List[Dict]) -> List[Dict]:
[proj.get("name", "N/A") for proj in unique_projects]
)
print(
f"LLM selected {len(unique_projects)} unique top projects: {project_names}"
f"LLM selected {len(unique_projects)} unique top projects: {project_names}"
)
return unique_projects

except json.JSONDecodeError as e:
print(f"ERROR: Error parsing LLM response: {e}")
print(f"ERROR: Raw response: {response_text}")

print("🔄 Falling back to first 7 projects")
print("Falling back to first 7 projects")
return projects_data[:7]

except Exception as e:
print(f"Error using LLM for project selection: {e}")
print("🔄 Falling back to first 7 projects")
print("Falling back to first 7 projects")

projects_data = []
for project in projects[:7]:
Expand All @@ -460,14 +460,14 @@ def fetch_and_display_github_info(github_url: str) -> Dict:
logger.info(f"{github_url}")
github_profile = fetch_github_profile(github_url)
if not github_profile:
print("\n❌ Failed to fetch GitHub profile details.")
print("\nFailed to fetch GitHub profile details.")
return {}

print("🔍 Fetching all repository details...")
print("Fetching all repository details...")
projects = fetch_all_github_repos(github_url)

if not projects:
print("\n❌ No repositories found or failed to fetch repository details.")
print("\nNo repositories found or failed to fetch repository details.")

profile_json = generate_profile_json(github_profile)
projects_json = generate_projects_json(projects)
Expand Down
6 changes: 3 additions & 3 deletions llm_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ def initialize_llm_provider(model_name: str) -> Any:
model_provider = MODEL_PROVIDER_MAPPING.get(model_name, ModelProvider.OLLAMA)
if model_provider == ModelProvider.GEMINI:
if not GEMINI_API_KEY:
logger.warning("⚠️ Gemini API key not found. Falling back to Ollama.")
logger.warning("Gemini API key not found. Falling back to Ollama.")
else:
logger.info(f"🔄 Using Google Gemini API provider with model {model_name}")
logger.info(f"Using Google Gemini API provider with model {model_name}")
provider = GeminiProvider(api_key=GEMINI_API_KEY)
else:
logger.info(f"🔄 Using Ollama provider with model {model_name}")
logger.info(f"Using Ollama provider with model {model_name}")
return provider
48 changes: 23 additions & 25 deletions pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ def _call_llm_for_section(
) -> Optional[Dict]:
try:
start_time = time.time()
logger.debug(
f"🔄 Extracting {section_name} section using {DEFAULT_MODEL}..."
)
logger.debug(f"Extracting {section_name} section using {DEFAULT_MODEL}...")

model_params = MODEL_PARAMETERS.get(
DEFAULT_MODEL, {"temperature": 0.1, "top_p": 0.9}
Expand All @@ -81,7 +79,7 @@ def _call_llm_for_section(
)
if not section_system_message:
logger.error(
f"Failed to render system message template for {section_name}"
f"Failed to render system message template for {section_name}"
)
return None

Expand Down Expand Up @@ -114,38 +112,38 @@ def _call_llm_for_section(
if json_start != -1 and json_end != -1:
response_text = response_text[json_start : json_end + 1]
parsed_data = json.loads(response_text)
logger.debug(f"Successfully extracted {section_name} section")
logger.debug(f"Successfully extracted {section_name} section")

transformed_data = transform_parsed_data(parsed_data)
end_time = time.time()
total_time = end_time - start_time
logger.debug(
f"⏱️ Total time for separate section extraction: {total_time:.2f} seconds"
f"Total time for separate section extraction: {total_time:.2f} seconds"
)

return transformed_data
except json.JSONDecodeError as e:
logger.error(f"Error parsing JSON for {section_name} section: {e}")
logger.error(f"Error parsing JSON for {section_name} section: {e}")
logger.error(f"Raw response: {response_text}")
return None

except Exception as e:
logger.error(f"Error calling LLM for {section_name} section: {e}")
logger.error(f"Error calling LLM for {section_name} section: {e}")
return None

def extract_basics_section(self, resume_text: str) -> Optional[Dict]:
prompt = self.template_manager.render_template(
"basics", text_content=resume_text
)
if not prompt:
logger.error("Failed to render basics template")
logger.error("Failed to render basics template")
return None
return self._call_llm_for_section("basics", resume_text, prompt, BasicsSection)

def extract_work_section(self, resume_text: str) -> Optional[Dict]:
prompt = self.template_manager.render_template("work", text_content=resume_text)
if not prompt:
logger.error("Failed to render work template")
logger.error("Failed to render work template")
return None
return self._call_llm_for_section("work", resume_text, prompt, WorkSection)

Expand All @@ -154,7 +152,7 @@ def extract_education_section(self, resume_text: str) -> Optional[Dict]:
"education", text_content=resume_text
)
if not prompt:
logger.error("Failed to render education template")
logger.error("Failed to render education template")
return None
return self._call_llm_for_section(
"education", resume_text, prompt, EducationSection
Expand All @@ -165,7 +163,7 @@ def extract_skills_section(self, resume_text: str) -> Optional[Dict]:
"skills", text_content=resume_text
)
if not prompt:
logger.error("Failed to render skills template")
logger.error("Failed to render skills template")
return None
return self._call_llm_for_section("skills", resume_text, prompt, SkillsSection)

Expand All @@ -174,7 +172,7 @@ def extract_projects_section(self, resume_text: str) -> Optional[Dict]:
"projects", text_content=resume_text
)
if not prompt:
logger.error("Failed to render projects template")
logger.error("Failed to render projects template")
return None
return self._call_llm_for_section(
"projects", resume_text, prompt, ProjectsSection
Expand All @@ -185,7 +183,7 @@ def extract_awards_section(self, resume_text: str) -> Optional[Dict]:
"awards", text_content=resume_text
)
if not prompt:
logger.error("Failed to render awards template")
logger.error("Failed to render awards template")
return None
return self._call_llm_for_section("awards", resume_text, prompt, AwardsSection)

Expand All @@ -198,22 +196,22 @@ def extract_json_from_text(self, resume_text: str) -> Optional[JSONResume]:

def extract_json_from_pdf(self, pdf_path: str) -> Optional[JSONResume]:
try:
logger.debug(f"📄 Extracting text from PDF: {pdf_path}")
logger.debug(f"Extracting text from PDF: {pdf_path}")
text_content = self.extract_text_from_pdf(pdf_path)

if not text_content:
logger.error("Failed to extract text from PDF")
logger.error("Failed to extract text from PDF")
return None

logger.debug(
f"Successfully extracted {len(text_content)} characters from PDF"
f"Successfully extracted {len(text_content)} characters from PDF"
)

logger.debug("🔄 Extracting all sections separately...")
logger.debug("Extracting all sections separately...")
return self._extract_all_sections_separately(text_content)

except Exception as e:
logger.error(f"Error during PDF to JSON extraction: {e}")
logger.error(f"Error during PDF to JSON extraction: {e}")
return None

def _extract_section_data(
Expand All @@ -229,7 +227,7 @@ def _extract_section_data(
}

if section_name not in section_extractors:
logger.error(f"Invalid section name: {section_name}")
logger.error(f"Invalid section name: {section_name}")
logger.error(f"Valid sections: {list(section_extractors.keys())}")
return None

Expand Down Expand Up @@ -291,10 +289,10 @@ def _extract_all_sections_separately(

if section_data:
complete_resume.update(section_data)
logger.debug(f"Successfully extracted {section_name} section")
logger.debug(f"Successfully extracted {section_name} section")
else:
logger.error(
f"⚠️ Failed to extract {section_name} section. Aborting extraction to prevent partial/invalid resume data."
f"Failed to extract {section_name} section. Aborting extraction to prevent partial/invalid resume data."
)
return None

Expand All @@ -305,19 +303,19 @@ def _extract_all_sections_separately(
try:
complete_resume["basics"] = Basics(**complete_resume["basics"])
except Exception as e:
logger.error(f"Error creating Basics object: {e}")
logger.error(f"Error creating Basics object: {e}")
complete_resume["basics"] = None

json_resume = JSONResume(**complete_resume)

end_time = time.time()
total_time = end_time - start_time
logger.info(
f"⏱️ Total time for separate section extraction: {total_time:.2f} seconds"
f"Total time for separate section extraction: {total_time:.2f} seconds"
)

return json_resume

except Exception as e:
logger.error(f"Error creating JSONResume object: {e}")
logger.error(f"Error creating JSONResume object: {e}")
return None
8 changes: 4 additions & 4 deletions prompts/template_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ def _load_templates(self):
if os.path.exists(template_path):
self._templates[section_name] = self.env.get_template(filename)
else:
print(f"⚠️ Template file not found: {template_path}")
print(f"[WARNING] Template file not found: {template_path}")
except Exception as e:
print(f" Error loading template {filename}: {e}")
print(f"[ERROR] Error loading template {filename}: {e}")

def get_available_sections(self) -> list:
"""
Expand All @@ -78,13 +78,13 @@ def render_template(self, section_name: str, **kwargs) -> Optional[str]:
Optional[str]: Rendered template string, or None if template not found
"""
if section_name not in self._templates:
print(f" Template not found for section: {section_name}")
print(f"[ERROR] Template not found for section: {section_name}")
print(f"Available sections: {self.get_available_sections()}")
return None

try:
template = self._templates[section_name]
return template.render(**kwargs)
except Exception as e:
print(f" Error rendering template for {section_name}: {e}")
print(f"[ERROR] Error rendering template for {section_name}: {e}")
return None
Loading