Skip to content

Commit 3972265

Browse files
committed
refactor(ai_generator): streamline profile summary generation and remove SEO content method
1 parent c46948e commit 3972265

File tree

3 files changed

+23
-85
lines changed

3 files changed

+23
-85
lines changed

api/main.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,9 @@ async def get_cached_github_profile(username: str) -> Dict[str, Any]:
6767

6868
try:
6969
ai_generator = AIDescriptionGenerator()
70-
about_data = ai_generator.generate_profile_summary(basic_profile)
71-
seo_data = ai_generator.generate_seo_contents(basic_profile)
72-
basic_profile['about'] = about_data
73-
basic_profile['seo'] = seo_data
70+
user_data = ai_generator.generate_profile_summary(basic_profile)
71+
basic_profile['about'] = user_data['about']
72+
basic_profile['seo'] = user_data['seo']
7473
except Exception as e:
7574
print(f"Failed to generate AI description: {str(e)}")
7675
basic_profile['about'] = None

modules/ai_generator.py

Lines changed: 19 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -12,71 +12,6 @@ def __init__(self):
1212
"""Initialize Groq client"""
1313
self.client = Groq(api_key=Settings.get_groq_key())
1414

15-
def generate_seo_contents(self, profile_data: dict):
16-
"""
17-
Generate a professional SEO-optimized profile content like title, description, keywords
18-
19-
Args:
20-
profile_data (dict): GitHub user profile data
21-
22-
Returns:
23-
dict: AI-generated SEO-optimized profile content
24-
"""
25-
prompt = (
26-
"Generate a concise, professional, and SEO-optimized profile snippet for a developer profile page."
27-
"\n\nReturn the output strictly in the following JSON format (without any additional commentary):"
28-
'\n{\n "title": "<Max 10 words. Format: FirstName (@username). Role passionate about [what they do]>",'
29-
'\n "description": "<Max 30 words (120–160 characters). Meta-style description that highlights skills and invites engagement>",'
30-
'\n "keywords": "<8–15 comma-separated keywords or phrases. Focus on Next.js-related terms, long-tail SEO phrases, and specific skills>"\n}'
31-
"\n\nUse this input data to personalize the content, handling missing or empty fields gracefully:"
32-
f"\n- Name: {profile_data.get('name', 'Anonymous Developer')}"
33-
f"\n- Username: {profile_data.get('username', 'username')}"
34-
f"\n- Followers: {profile_data.get('followers', 0)} (highlight if over 500)"
35-
f"\n- Public Repositories: {profile_data.get('public_repos', 0)} (highlight if over 20)"
36-
f"\n- Bio: {profile_data.get('bio', '')} (infer core skills or passions)"
37-
f"\n- README: {profile_data.get('readme_content', '')} (extract unique traits or standout projects)"
38-
"\n\nIf data is sparse, infer likely skills or focus areas. Avoid filler or generic phrases. Prioritize precision and clarity."
39-
)
40-
41-
response = self.client.chat.completions.create(
42-
messages=[
43-
{
44-
"role": "system",
45-
"content": "You are an SEO-optimized profile content generator for developer portfolios and GitHub profiles. Create search engine friendly, professional profile summaries that enhance discoverability and professional presence. Generate content in natural paragraph format without headings, lists, or bullet points. Focus on keyword integration, meta-friendly descriptions, and compelling copy that drives engagement and showcases technical expertise effectively. Your output should be properly formatted JSON when requested, with each field containing well-crafted, SEO-optimized content.",
46-
},
47-
{"role": "user", "content": prompt},
48-
],
49-
model="llama-3.1-8b-instant",
50-
response_format={"type": "json_object"},
51-
)
52-
if not response.choices or response.choices[0].message.content == "":
53-
raise Exception("No response from AI model")
54-
try:
55-
result = json.loads(response.choices[0].message.content)
56-
except json.JSONDecodeError as e:
57-
raise Exception(f"AI response was not valid JSON. Content: {response.choices[0].message.content}") from e
58-
59-
title = result["title"]
60-
description = result["description"]
61-
keywords = result["keywords"]
62-
63-
if not (title and description and keywords):
64-
missing = []
65-
if not title:
66-
missing.append("title")
67-
if not description:
68-
missing.append("description")
69-
if not keywords:
70-
missing.append("keywords")
71-
raise Exception(
72-
f"AI response missing required SEO fields: {', '.join(missing)}. Received: {result}"
73-
)
74-
return {
75-
"title": title,
76-
"description": description,
77-
"keywords": keywords,
78-
}
79-
8015
def generate_profile_summary(self, profile_data):
8116
"""
8217
Generate a professional profile summary
@@ -88,20 +23,24 @@ def generate_profile_summary(self, profile_data):
8823
str: AI-generated profile summary
8924
"""
9025
prompt = (
91-
"Write only the final profile summary text — no introductions, no explanations, and no meta sentences."
92-
"\nCraft a Concise, SEO-optimized first-person profile description that:"
93-
"\n- Highlights the developer's strongest technical skills and expertise"
94-
"\n- Concise and on to the point"
95-
"\n- Uses simple, direct language without excessive superlatives"
96-
"\n- Incorporates unique details from the profile, bio and readme.md (if available)"
97-
"\n- Limits the bio to 2-3 sentences"
98-
"\n\nProfile Details:"
99-
f"\nName: {profile_data['name']}"
100-
f"\n- Followers: {profile_data['followers']} (indicating professional network and influence)"
101-
f"\n- Public Repositories: {profile_data['public_repos']} (demonstrating active development)"
102-
f"\n- Bio: {profile_data['bio']}"
103-
"\n\nGenerate a short, engaging summary."
104-
f"\n- README: {profile_data['readme_content']}"
26+
"Generate a valid JSON developer profile. Return ONLY the JSON object—no commentary, markdown, or prefixes.\n"
27+
"\nOUTPUT FORMAT:\n"
28+
"{\n \"about\": \"<4-6 sentence first-person summary>\",\n \"seo\": {\n \"title\": \"<Max 10 words: FirstName (@username). Role passionate about [focus]>\",\n \"description\": \"<120-160 char SEO meta highlighting key skills>\",\n \"keywords\": \"<8-15 comma-separated keywords: Next.js, long-tail dev terms, specific skills>\"\n }\n}\n"
29+
"\nRULES:\n"
30+
"- All keys required. Use empty strings if data missing—never null\n"
31+
"- Never alter structure or add fields\n"
32+
"- About: First-person, 4-6 sentences, developer's strongest technical skills and expertise, no superlatives\n"
33+
"- SEO title: Max 10 words, follow format\n"
34+
"- SEO description: 120-160 chars\n"
35+
"- Keywords: 8-15 SEO phrases (Next.js, frameworks, inferred skills)\n"
36+
"- Infer conservatively if data sparse\n"
37+
"\nPROFILE DATA:\n"
38+
f"Name: {profile_data.get('name', '')}\n"
39+
f"Username: {profile_data.get('username', '')}\n"
40+
f"Followers: {profile_data.get('followers', '')}\n"
41+
f"Public Repos: {profile_data.get('public_repos', '')}\n"
42+
f"Bio: {profile_data.get('bio', '')}\n"
43+
f"README: {profile_data.get('readme_content', '')}"
10544
)
10645

10746
response = self.client.chat.completions.create(
@@ -117,7 +56,7 @@ def generate_profile_summary(self, profile_data):
11756
if not response.choices or response.choices[0].message.content == "":
11857
raise Exception("No response from AI model")
11958

120-
return response.choices[0].message.content
59+
return json.loads(response.choices[0].message.content)
12160

12261
def generate_activity_summary(self, contributions):
12362
"""

utils/user.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,6 @@ def get_user_data(username, force=True):
7474
profile_data['activity_summary'] = activity_summary if activity_summary else {}
7575

7676
# Add summaries to profile data
77-
profile_data['profile_summary'] = profile_summary
77+
profile_data['profile_summary'] = profile_summary['about']
7878

7979
return profile_data

0 commit comments

Comments
 (0)