chelouche9 commited on
Commit
c14cd7f
Β·
1 Parent(s): 5cf4465

feat: support multiple repos

Browse files
Files changed (1) hide show
  1. app.py +56 -50
app.py CHANGED
@@ -7,29 +7,28 @@ import shutil
7
  from openai import OpenAI
8
  import dotenv
9
 
10
- def generate_prompt(repo_url, role, seniority, assignment_details, repo_data, focus_areas=""):
11
- """Generates the AI analysis prompt with repo details."""
12
- return f"""
13
- You are an AI expert in evaluating software engineering candidates based on their GitHub repositories. Your goal is to assess the quality, organization, and best practices of the submitted code repository. Below is the candidate's information:
14
 
15
  ### Candidate Information:
16
  - **Role Applied For**: {role}
17
  - **Seniority Level**: {seniority}
18
- - **GitHub Repository URL**: {repo_url}
19
 
20
  ### Guidelines:
21
  - Focus on the candidate's ability to write clean, efficient, and maintainable code.
22
- - Take into consideration the seniority level when evaluating the code.
23
- - Focus on the assignment details provided. What was requested of him and how he responded to it.
24
 
25
  ### Assignment Details:
26
  {assignment_details}
27
 
28
  ### Repository Analysis:
29
- You are provided with the repository's cloned structure and its contents. Analyze the following aspects:
30
- {repo_data}
31
 
32
- ### Additional Evaluation Criteria:
33
  1. **Code Organization & Architecture**
34
  2. **Code Quality & Best Practices**
35
  3. **Language Proficiency & Best Practices**
@@ -39,15 +38,15 @@ def generate_prompt(repo_url, role, seniority, assignment_details, repo_data, fo
39
  {focus_areas}
40
 
41
  ### **Final Score Calculation**
42
- - Score the repository **out of 100** based on the criteria above.
43
  - Justify the **score** by explaining the candidate’s strengths and weaknesses.
44
 
45
  ### **Expected Output:**
46
- - **Strengths**: What is done well?
47
- - **Weaknesses**: What needs improvement?
48
- - **Final Score (0-100)**: Provide a numeric score with an explanation.
49
- - **Summary**: Briefly summarize the candidate’s proficiency based on this analysis.
50
  """
 
51
 
52
  # Load environment variables
53
  dotenv.load_dotenv()
@@ -61,49 +60,57 @@ def authenticate(password):
61
  return "❌ Incorrect password! Access denied.", None
62
  return None, "βœ… Access granted! You may proceed."
63
 
64
- def analyze_repo(repo_url, role, seniority, assignment_details, focus_areas, password):
65
  auth_error, auth_success = authenticate(password)
66
  if auth_error:
67
  return auth_error, gr.update(visible=False) # If incorrect password, return error
68
 
69
- """Clone and analyze a GitHub repository with a loading state."""
70
- if not repo_url.startswith("https://github.com/"):
71
- return "❌ Invalid GitHub URL!", gr.update(visible=False)
 
 
72
 
73
- # Extract repo details
74
- repo_name = repo_url.split("/")[-1]
75
  temp_dir = tempfile.mkdtemp()
 
 
76
 
77
  try:
78
- progress = gr.update(value="πŸ”„ Cloning repository...", visible=True)
79
-
80
- # Clone the repo
81
- repo_path = os.path.join(temp_dir, repo_name)
82
- git.Repo.clone_from(repo_url, repo_path)
83
 
84
- progress = gr.update(value="πŸ“‚ Analyzing repository structure...", visible=True)
85
-
86
- # Gather repository file structure and contents
87
- repo_data = ""
88
- file_count = 0 # Initialize file counter
89
-
90
- for root, _, filenames in os.walk(repo_path):
91
- for file in filenames:
92
- file_count += 1 # Increment file counter
93
- file_path = os.path.join(root, file)
94
-
95
- try:
96
- with open(file_path, "r", encoding="utf-8") as f:
97
- file_content = f.read()
98
- repo_data += f"\n**File {file_count}:** {file_path.replace(repo_path, '')}\n```\n{file_content[:1000]}\n```\n"
99
- except Exception:
100
- repo_data += f"\n**File {file_count}:** {file_path.replace(repo_path, '')} (⚠️ Cannot read binary file)\n"
 
 
 
 
 
 
 
 
 
 
101
 
102
  progress = gr.update(value="πŸ€– Sending data to AI for evaluation...", visible=True)
103
 
104
  # AI-based evaluation
105
  evaluation = f"βœ… **Evaluation for Role: {role}**\n\n"
106
- evaluation += f"πŸ“‚ Repository `{repo_name}` has `{file_count}` files.\n"
107
  evaluation += f"πŸ’‘ Key focus areas: {focus_areas}\n\n"
108
  evaluation += "**πŸ” Code Quality Analysis:**\n"
109
 
@@ -112,7 +119,7 @@ def analyze_repo(repo_url, role, seniority, assignment_details, focus_areas, pas
112
  messages=[
113
  {
114
  "role": "user",
115
- "content": generate_prompt(repo_url, role, seniority, assignment_details, repo_data, focus_areas)
116
  }
117
  ]
118
  )
@@ -123,7 +130,7 @@ def analyze_repo(repo_url, role, seniority, assignment_details, focus_areas, pas
123
  return evaluation, progress
124
 
125
  except Exception as e:
126
- return f"❌ Error analyzing repository: {str(e)}", gr.update(visible=False)
127
 
128
  finally:
129
  shutil.rmtree(temp_dir) # Cleanup
@@ -138,10 +145,9 @@ with gr.Blocks() as app:
138
  ["Junior", "Mid", "Senior"],
139
  label="Seniority Level",
140
  value="Mid"
141
-
142
  )
143
  assignment_details = gr.Textbox(label="Assignment Details", lines=8)
144
- repo_url = gr.Textbox(label="GitHub Repository URL")
145
  focus_areas = gr.Textbox(label="Optional Focus Areas (e.g., Clean Code, Performance)")
146
 
147
  output = gr.Markdown()
@@ -150,8 +156,8 @@ with gr.Blocks() as app:
150
  submit_btn = gr.Button("πŸ” Evaluate")
151
 
152
  submit_btn.click(
153
- fn=analyze_repo,
154
- inputs=[repo_url, role, seniority, assignment_details, focus_areas, password],
155
  outputs=[output, progress]
156
  )
157
 
 
7
  from openai import OpenAI
8
  import dotenv
9
 
10
+ def generate_prompt(repos_data, role, seniority, assignment_details, focus_areas=""):
11
+ """Generates the AI analysis prompt with multiple repo details."""
12
+ prompt = f"""
13
+ You are an AI expert in evaluating software engineering candidates based on their GitHub repositories. Your goal is to assess the quality, organization, and best practices of the submitted code repositories. Below is the candidate's information:
14
 
15
  ### Candidate Information:
16
  - **Role Applied For**: {role}
17
  - **Seniority Level**: {seniority}
 
18
 
19
  ### Guidelines:
20
  - Focus on the candidate's ability to write clean, efficient, and maintainable code.
21
+ - Consider the seniority level when evaluating the code.
22
+ - Consider the assignment details and how the candidate responded.
23
 
24
  ### Assignment Details:
25
  {assignment_details}
26
 
27
  ### Repository Analysis:
28
+ Below are the repositories submitted by the candidate:
29
+ {repos_data}
30
 
31
+ ### Evaluation Criteria:
32
  1. **Code Organization & Architecture**
33
  2. **Code Quality & Best Practices**
34
  3. **Language Proficiency & Best Practices**
 
38
  {focus_areas}
39
 
40
  ### **Final Score Calculation**
41
+ - Score each repository **out of 100** and provide an overall weighted score.
42
  - Justify the **score** by explaining the candidate’s strengths and weaknesses.
43
 
44
  ### **Expected Output:**
45
+ - **Per Repository Analysis**: A detailed breakdown of strengths and weaknesses.
46
+ - **Overall Candidate Summary**: A final evaluation of their coding skills across all repositories.
47
+ - **Final Score (0-100)**: A numeric score with justification.
 
48
  """
49
+ return prompt
50
 
51
  # Load environment variables
52
  dotenv.load_dotenv()
 
60
  return "❌ Incorrect password! Access denied.", None
61
  return None, "βœ… Access granted! You may proceed."
62
 
63
+ def analyze_repos(repo_urls, role, seniority, assignment_details, focus_areas, password):
64
  auth_error, auth_success = authenticate(password)
65
  if auth_error:
66
  return auth_error, gr.update(visible=False) # If incorrect password, return error
67
 
68
+ """Clone and analyze multiple GitHub repositories."""
69
+ repo_urls = [url.strip() for url in repo_urls.split(",") if url.strip()]
70
+
71
+ if not all(url.startswith("https://github.com/") for url in repo_urls):
72
+ return "❌ One or more URLs are invalid!", gr.update(visible=False)
73
 
 
 
74
  temp_dir = tempfile.mkdtemp()
75
+ repos_data = ""
76
+ total_files = 0
77
 
78
  try:
79
+ progress = gr.update(value="πŸ”„ Cloning repositories...", visible=True)
 
 
 
 
80
 
81
+ for repo_url in repo_urls:
82
+ repo_name = repo_url.split("/")[-1]
83
+ repo_path = os.path.join(temp_dir, repo_name)
84
+
85
+ try:
86
+ git.Repo.clone_from(repo_url, repo_path)
87
+ except Exception as e:
88
+ repos_data += f"\n❌ Failed to clone `{repo_name}`: {str(e)}\n"
89
+ continue
90
+
91
+ repo_data = f"\nπŸ“‚ **Repository: {repo_name}**\n"
92
+ file_count = 0
93
+
94
+ for root, _, filenames in os.walk(repo_path):
95
+ for file in filenames:
96
+ file_count += 1
97
+ file_path = os.path.join(root, file)
98
+
99
+ try:
100
+ with open(file_path, "r", encoding="utf-8") as f:
101
+ file_content = f.read()
102
+ repo_data += f"\n**File {file_count}:** {file_path.replace(repo_path, '')}\n```\n{file_content[:1000]}\n```\n"
103
+ except Exception:
104
+ repo_data += f"\n**File {file_count}:** {file_path.replace(repo_path, '')} (⚠️ Cannot read binary file)\n"
105
+
106
+ repos_data += repo_data
107
+ total_files += file_count
108
 
109
  progress = gr.update(value="πŸ€– Sending data to AI for evaluation...", visible=True)
110
 
111
  # AI-based evaluation
112
  evaluation = f"βœ… **Evaluation for Role: {role}**\n\n"
113
+ evaluation += f"πŸ“‚ `{len(repo_urls)}` repositories analyzed, containing `{total_files}` files.\n"
114
  evaluation += f"πŸ’‘ Key focus areas: {focus_areas}\n\n"
115
  evaluation += "**πŸ” Code Quality Analysis:**\n"
116
 
 
119
  messages=[
120
  {
121
  "role": "user",
122
+ "content": generate_prompt(repos_data, role, seniority, assignment_details, focus_areas)
123
  }
124
  ]
125
  )
 
130
  return evaluation, progress
131
 
132
  except Exception as e:
133
+ return f"❌ Error analyzing repositories: {str(e)}", gr.update(visible=False)
134
 
135
  finally:
136
  shutil.rmtree(temp_dir) # Cleanup
 
145
  ["Junior", "Mid", "Senior"],
146
  label="Seniority Level",
147
  value="Mid"
 
148
  )
149
  assignment_details = gr.Textbox(label="Assignment Details", lines=8)
150
+ repo_urls = gr.Textbox(label="GitHub Repository URLs (comma-separated)")
151
  focus_areas = gr.Textbox(label="Optional Focus Areas (e.g., Clean Code, Performance)")
152
 
153
  output = gr.Markdown()
 
156
  submit_btn = gr.Button("πŸ” Evaluate")
157
 
158
  submit_btn.click(
159
+ fn=analyze_repos,
160
+ inputs=[repo_urls, role, seniority, assignment_details, focus_areas, password],
161
  outputs=[output, progress]
162
  )
163