Skip to content

Commit 9332c77

Browse files
committed
fix: final gemini tweaks (utcnow + robust AI gather)
1 parent 8d86d8d commit 9332c77

2 files changed

Lines changed: 30 additions & 45 deletions

File tree

modules/github_fetcher.py

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ async def validate_github_username(username: str) -> bool:
5252
data = response.json()
5353
return data.get('type') == 'User'
5454
except httpx.HTTPError:
55-
return True # Fall back to pattern validation on API error
55+
return True
5656

5757
@staticmethod
5858
async def fetch_user_profile(username: str) -> dict:
@@ -61,8 +61,8 @@ async def fetch_user_profile(username: str) -> dict:
6161
if not await GitHubProfileFetcher.validate_github_username(username):
6262
raise ValueError(f"Invalid GitHub username: '{username}'")
6363

64-
one_year_ago = (datetime.now() - timedelta(days=365)).isoformat() + 'Z'
65-
one_year_ago_dt = datetime.now() - timedelta(days=365) # pre-calculated for loops
64+
one_year_ago_dt = datetime.utcnow() - timedelta(days=365)
65+
one_year_ago = one_year_ago_dt.isoformat() + 'Z'
6666

6767
graphql_query = {
6868
"query": f"""
@@ -109,7 +109,7 @@ async def fetch_user_profile(username: str) -> dict:
109109

110110
graphql_data = graphql_response.json().get('data', {}).get('user', {})
111111
if not graphql_data:
112-
raise ValueError(f"User '{username}' not found or query returned no data.")
112+
raise ValueError(f"User '{username}' not found")
113113

114114
pr_merged_last_year = sum(
115115
1 for pr in graphql_data.get('pullRequests', {}).get('nodes', [])
@@ -155,56 +155,44 @@ async def fetch_user_profile(username: str) -> dict:
155155

156156
@staticmethod
157157
async def social_accounts(username):
158-
"""Fetch social accounts of the user from GitHub API.
159-
If the API returns a 404, it attempts to extract social links from the user's README.md.
160-
161-
Returns:
162-
list: A list of dictionaries, each representing a social account.
163-
"""
158+
"""Fetch social accounts. Returns list or {"error": "..."} for consistency."""
164159
try:
165160
base_url = f"https://api.github.com/users/{username}/social_accounts"
166161
async with httpx.AsyncClient() as client:
167-
user_response = await client.get(
162+
resp = await client.get(
168163
base_url,
169164
headers={
170165
"Accept": "application/vnd.github.v3+json",
171-
"Authorization": f"token {Settings.get_github_token()}",
166+
"Authorization": f"token {Settings.get_github_token()}"
172167
}
173168
)
174-
user_response.raise_for_status()
175-
return user_response.json()
169+
resp.raise_for_status()
170+
return resp.json()
176171
except httpx.HTTPStatusError as e:
177172
if e.response.status_code == 404:
178173
return await GitHubProfileFetcher.get_social_from_readme(username)
179-
return []
174+
return {"error": f"HTTP Error: {e.response.status_code}"}
180175
except Exception as e:
181176
logger.exception("Unexpected error in social_accounts for user %s", username)
182-
return []
177+
return {"error": "Failed to fetch social accounts"}
183178

184179
@staticmethod
185180
async def get_social_from_readme(username):
186-
"""Extract LinkedIn link from user's README.md (simplified - only LinkedIn for reliability)"""
181+
"""Extract LinkedIn link from README (simplified for reliability)"""
187182
try:
188-
readme_url = f"https://api.github.com/repos/{username}/{username}/readme"
183+
url = f"https://api.github.com/repos/{username}/{username}/readme"
189184
async with httpx.AsyncClient() as client:
190-
readme_response = await client.get(
191-
readme_url,
185+
r = await client.get(
186+
url,
192187
headers={
193188
"Accept": "application/vnd.github.v3+json",
194-
"Authorization": f"token {Settings.get_github_token()}",
189+
"Authorization": f"token {Settings.get_github_token()}"
195190
}
196191
)
197-
readme_response.raise_for_status()
198-
readme_content = base64.b64decode(readme_response.json()['content']).decode('utf-8')
199-
200-
social_accounts_list = []
201-
linkedin_match = re.search(r'linkedin\.com/in/([a-zA-Z0-9-]+)', readme_content, re.I)
202-
if linkedin_match:
203-
social_accounts_list.append({
204-
"provider": "linkedin",
205-
"url": f"https://linkedin.com/in/{linkedin_match.group(1)}"
206-
})
207-
return social_accounts_list
192+
r.raise_for_status()
193+
content = base64.b64decode(r.json()['content']).decode('utf-8')
194+
match = re.search(r'linkedin\.com/in/([a-zA-Z0-9-]+)', content, re.I)
195+
return [{"provider": "linkedin", "url": f"https://linkedin.com/in/{match.group(1)}"}] if match else []
208196
except Exception as e:
209197
logger.exception("Unexpected error in get_social_from_readme for user %s", username)
210198
return []

utils/user.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ async def get_user_data(username: str, force: bool = True) -> dict:
6060
if res.status_code == 200:
6161
return res.json()
6262

63-
# Parallel fetch profile + contributions
63+
# Parallel fetch
6464
profile_data, contributions_data = await asyncio.gather(
6565
GitHubProfileFetcher.fetch_user_profile(username),
6666
asyncio.to_thread(
@@ -70,23 +70,20 @@ async def get_user_data(username: str, force: bool = True) -> dict:
7070
)
7171
)
7272

73-
# Early return if GitHub fetch failed
7473
if "error" in profile_data:
7574
return profile_data
7675

7776
ai_generator = AIDescriptionGenerator()
7877

79-
# Parallel AI summary generation
80-
try:
81-
profile_summary, activity_summary = await asyncio.gather(
82-
asyncio.to_thread(ai_generator.generate_profile_summary, profile_data),
83-
asyncio.to_thread(ai_generator.generate_activity_summary, contributions_data) if contributions_data else None,
84-
return_exceptions=True
85-
)
86-
except Exception as e:
87-
logger.exception("Failed to generate AI summaries for user %s", username)
88-
profile_summary = None
89-
activity_summary = None
78+
# Robust parallel AI summaries
79+
ai_tasks = [asyncio.to_thread(ai_generator.generate_profile_summary, profile_data)]
80+
if contributions_data:
81+
ai_tasks.append(asyncio.to_thread(ai_generator.generate_activity_summary, contributions_data))
82+
83+
results = await asyncio.gather(*ai_tasks, return_exceptions=True)
84+
85+
profile_summary = results[0] if not isinstance(results[0], BaseException) else None
86+
activity_summary = results[1] if len(results) > 1 and not isinstance(results[1], BaseException) else None
9087

9188
if contributions_data:
9289
profile_data['activity_summary'] = activity_summary if activity_summary else {}

0 commit comments

Comments
 (0)