Spaces:
Sleeping
Sleeping
import gradio as gr | |
import datetime | |
import random | |
from collections import defaultdict | |
from utils.constants import TASK_DIFFICULTIES | |
from utils.data_helpers import smart_label_converter, clean_text, extract_actions_from_feedback | |
from utils.api_clients import initialize_api_clients | |
from utils.embedding_model import initialize_embedding_model | |
from utils.summarizer import initialize_summarizer | |
from utils.constants import course_suggestions | |
from modules.rag import load_docs, memo_rag_engine, batch_ingest_from_classcentral | |
from modules.task_management import display_tasks, add_reward, calculate_progress, claim_reward, add_task, add_course_to_memo, mark_step_completed, calculate_visual_progress, reset_weekly_data | |
from modules.analysis import analyze_linkedin, analyze_github, analyze_scraped_linkedin_profile, analyze_apify_dataset_ui | |
from modules.analysis import fetch_and_analyze_linkedin | |
from utils.constants import completed_tasks | |
from modules.memory import save_to_memory, recall_from_memory | |
import textwrap | |
from modules.analysis import fetch_and_analyze_linkedin # Import the function for LinkedIn analysis | |
# ==== Global Variables ==== | |
completed_tasks = set() | |
memo_data = [] | |
visual_steps = [] | |
# ==== API Clients & Models ==== | |
pc, pine_index, APIFY_TOKEN, OPENAI_API_KEY, TAVILY_API_KEY, client = initialize_api_clients() | |
embedding_model = initialize_embedding_model() | |
summarizer = initialize_summarizer() | |
# ==== Gradio UI Components ==== | |
class RoadmapUnlockManager: | |
def __init__(self): | |
self.unlocked = False | |
def unlock_roadmap(self): | |
self.unlocked = True | |
return gr.update(visible=True) | |
def get_roadmap_visibility(self): | |
return gr.update(visible=self.unlocked) | |
roadmap_unlock = RoadmapUnlockManager() | |
with gr.Blocks(theme="NoCrypt/[email protected]", css=""" | |
@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro&display=swap'); | |
body { | |
font-family: 'Source Sans Pro', sans-serif; | |
background-color: #121212; | |
color: #f0f0f0; | |
} | |
#nickname-box { | |
max-width: 300px; | |
margin: 0 auto; | |
padding: 20px; | |
background-color: #1e1e1e; | |
border-radius: 12px; | |
box-shadow: 0px 0px 10px rgba(0,0,0,0.2); | |
} | |
#planner-card { | |
max-width: 720px; | |
margin: 0 auto; | |
padding: 28px; | |
background-color: #1e1e1e; | |
border-radius: 16px; | |
box-shadow: 0 0 12px rgba(0, 0, 0, 0.4); | |
} | |
#planner-card input, | |
#planner-card textarea, | |
#planner-card .gr-button { | |
font-size: 14px; | |
padding: 8px 12px; | |
border-radius: 8px; | |
} | |
#planner-card .gr-button { | |
background-color: #3a3aff; | |
color: #f0f0f0; | |
font-weight: bold; | |
} | |
#planner-card label { | |
font-weight: 600; | |
color: #f0f0f0; | |
} | |
#planner-card .gr-tab { | |
margin-top: 12px; | |
} | |
#linky-tab { | |
background-color: #1e1e1e !important; | |
color: #f0f0f0 !important; | |
padding: 24px; | |
border-radius: 16px; | |
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); | |
} | |
#linky-tab .gr-block, | |
#linky-tab .gr-column, | |
#linky-tab .gr-panel { | |
background-color: transparent !important; | |
color: inherit; | |
box-shadow: none; | |
} | |
#linky-tab input, | |
#linky-tab textarea { | |
background-color: #2c2c2c !important; | |
color: #f0f0f0 !important; | |
border: 1px solid #444 !important; | |
border-radius: 6px; | |
} | |
#linky-tab .gr-button { | |
background-color: #4444aa !important; | |
color: #f0f0f0 !important; | |
border-radius: 6px; | |
} | |
#dds-logo img { | |
max-width: 200px; | |
display: block; | |
margin: 0 auto 15px; | |
} | |
#user-card { | |
background-color: #2b2b2b; | |
border: 1px solid #444; | |
border-radius: 12px; | |
padding: 24px; | |
margin-top: 20px; | |
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); | |
color: #e0e0e0; | |
} | |
#user-card input, | |
#user-card textarea { | |
background-color: #3a3a3a !important; | |
color: #e0e0e0 !important; | |
border: 1px solid #555; | |
border-radius: 6px; | |
padding: 10px; | |
} | |
#user-card label { | |
color: #cccccc; | |
} | |
@media (max-width: 768px) { | |
.gr-row { | |
flex-direction: column !important; | |
} | |
#user-card { | |
margin-top: 20px; | |
} | |
} | |
.gradio-container { | |
color: #f0f0f0 !important; | |
background-color: #121212 !important; | |
} | |
.prose { | |
color: #f0f0f0 !important; | |
} | |
.gr-textbox, | |
.gr-markdown, | |
.gr-markdown div, | |
.gr-markdown p { | |
color: #f0f0f0 !important; | |
background: transparent; | |
} | |
label { | |
color: #cccccc !important; | |
} | |
input, textarea { | |
background-color: #1e1e1e !important; | |
color: #f0f0f0 !important; | |
border: 1px solid #444 !important; | |
} | |
.gr-button { | |
color: #f0f0f0 !important; | |
font-weight: bold; | |
background-color: #3a3aff !important; | |
} | |
""") as app: | |
user_id_state = gr.State() | |
roadmap_unlock = RoadmapUnlockManager() | |
start_date = gr.Textbox(label="π Start Date", value=str(datetime.date.today())) | |
with gr.Tabs(): | |
with gr.Tab("β¨ Welcome"): | |
with gr.Row(equal_height=True): | |
# LEFT: Intro | |
with gr.Column(scale=2): | |
gr.Markdown(""" | |
# π Welcome to Career Buddy! | |
**Your AI-powered career planner** for LinkedIn, GitHub, and goal-tracking.** | |
If you enjoy this project and want to help me beat OpenAI costs; support me below | |
""") | |
gr.HTML("""<a href="https://ko-fi.com/wishingonstars" target="_blank"><img src="https://cdn.prod.website-files.com/5c14e387dab576fe667689cf/670f5a0172b90570b1c21dab_kofi_logo.png" alt="Support Me on Ko-fi" style="width: 150px;"></a>""") | |
gr.Markdown(""" | |
### π Get Started | |
1. **Enter your nickname** to personalize your journey. | |
2. **Set your weekly goal** to stay on track. | |
3. **Explore the tabs** for LinkedIn/GitHub analysis, smart planning, and more! | |
""") | |
# RIGHT: User Input | |
with gr.Column(scale=1, elem_id="user-card"): | |
gr.Markdown("## Your Journey Starts Here") | |
nickname_input = gr.Textbox(label="Enter your Nickname", placeholder="e.g., DataScientistPro", interactive=True) | |
weekly_goal_input = gr.Textbox(label="What's your weekly career goal?", placeholder="e.g., Apply to 5 jobs, finish a Python course", interactive=True) | |
with gr.Row(): | |
save_btn = gr.Button("Save Profile") | |
load_btn = gr.Button("Load Profile") | |
gr.Markdown("### Your Progress") | |
progress_output = gr.Markdown("", elem_id="progress-output") | |
save_btn.click( | |
fn=lambda nickname, goal: save_user_profile(nickname, goal), | |
inputs=[nickname_input, weekly_goal_input], | |
outputs=progress_output | |
) | |
load_btn.click( | |
fn=lambda: load_user_profile(), | |
inputs=[], | |
outputs=[nickname_input, weekly_goal_input, progress_output] | |
) | |
with gr.Tab("π Linky (LinkedIn Analyzer)", elem_id="linky-tab"): | |
with gr.Row(): | |
with gr.Column(scale=1): | |
linkedin_url_input = gr.Textbox(label="LinkedIn Profile URL", placeholder="Paste your LinkedIn profile URL here", interactive=True) | |
analyze_linkedin_btn = gr.Button("Analyze LinkedIn Profile") | |
with gr.Column(scale=2): | |
linkedin_analysis_output = gr.Markdown("", label="LinkedIn Analysis Results") | |
# When the button is clicked, analyze the LinkedIn profile | |
analyze_linkedin_btn.click( | |
fn=fetch_and_analyze_linkedin, | |
inputs=[linkedin_url_input], | |
outputs=linkedin_analysis_output | |
) | |
with gr.Tab("π GitGuru (GitHub Reviewer)"): | |
with gr.Row(): | |
with gr.Column(scale=1): | |
github_readme_input = gr.Textbox(label="GitHub README Content", placeholder="Paste your main GitHub README content here", lines=10, interactive=True) | |
analyze_github_btn = gr.Button("Analyze GitHub README") | |
with gr.Column(scale=2): | |
github_analysis_output = gr.Markdown("", label="GitHub Analysis Results") | |
analyze_github_btn.click( | |
fn=analyze_github, | |
inputs=[github_readme_input], | |
outputs=github_analysis_output | |
) | |
with gr.Tab("π§ Smart Planner"): | |
with gr.Row(): | |
with gr.Column(scale=1): | |
planner_goal_input = gr.Textbox(label="Your Goal", placeholder="e.g., Become a Data Scientist", interactive=True) | |
planner_difficulty_input = gr.Dropdown(label="Difficulty", choices=TASK_DIFFICULTIES, value="Medium", interactive=True) | |
planner_generate_btn = gr.Button("Generate Roadmap") | |
with gr.Column(scale=2): | |
roadmap_output = gr.Markdown("", label="Career Roadmap") | |
planner_generate_btn.click( | |
fn=lambda goal, difficulty: generate_roadmap(goal, difficulty, pc, pine_index, client), | |
inputs=[planner_goal_input, planner_difficulty_input], | |
outputs=roadmap_output | |
) | |
with gr.Tab("π― Task Tracker"): | |
with gr.Row(): | |
with gr.Column(scale=1): | |
task_name_input = gr.Textbox(label="Task Name", placeholder="e.g., Complete Python course", interactive=True) | |
task_type_input = gr.Dropdown(label="Task Type", choices=["Learning", "Networking", "Project", "Application"], value="Learning", interactive=True) | |
task_add_btn = gr.Button("Add Task") | |
gr.Markdown("### Mark Task Steps Completed") | |
task_step_input = gr.Textbox(label="Step to Mark Completed", placeholder="e.g., Chapter 1 of Python course", interactive=True) | |
task_mark_completed_btn = gr.Button("Mark Step Completed") | |
gr.Markdown("### Rewards") | |
reward_amount_input = gr.Number(label="Reward Amount", value=10, interactive=True) | |
reward_claim_btn = gr.Button("Claim Reward") | |
reset_weekly_btn = gr.Button("Reset Weekly Data") | |
with gr.Column(scale=2): | |
tasks_display = gr.Markdown("", label="Your Tasks") | |
progress_bar = gr.HTML("", label="Weekly Progress") | |
rewards_display = gr.Markdown("", label="Your Rewards") | |
task_add_btn.click( | |
fn=lambda user_id, task_name, task_type: add_task(user_id, task_name, task_type, tasks_display, progress_bar, rewards_display), | |
inputs=[user_id_state, task_name_input, task_type_input], | |
outputs=[tasks_display, progress_bar, rewards_display] | |
) | |
task_mark_completed_btn.click( | |
fn=lambda user_id, step: mark_step_completed(user_id, step, tasks_display, progress_bar, rewards_display), | |
inputs=[user_id_state, task_step_input], | |
outputs=[tasks_display, progress_bar, rewards_display] | |
) | |
reward_claim_btn.click( | |
fn=lambda user_id, amount: claim_reward(user_id, amount, rewards_display), | |
inputs=[user_id_state, reward_amount_input], | |
outputs=rewards_display | |
) | |
reset_weekly_btn.click( | |
fn=lambda user_id: reset_weekly_data(user_id, tasks_display, progress_bar, rewards_display), | |
inputs=[user_id_state], | |
outputs=[tasks_display, progress_bar, rewards_display] | |
) | |
with gr.Tab("π Memo (Course Recommender)"): | |
with gr.Row(): | |
with gr.Column(scale=1): | |
memo_query_input = gr.Textbox(label="Ask about a course or topic", placeholder="e.g., Best Python courses for data science", interactive=True) | |
memo_search_btn = gr.Button("Search Courses") | |
gr.Markdown("### Add Course to Memo") | |
memo_course_name_input = gr.Textbox(label="Course Name", interactive=True) | |
memo_course_url_input = gr.Textbox(label="Course URL", interactive=True) | |
memo_add_course_btn = gr.Button("Add Course") | |
with gr.Column(scale=2): | |
memo_output = gr.Markdown("", label="Course Recommendations") | |
memo_search_btn.click( | |
fn=lambda query: memo_rag_engine(query, pine_index, embedding_model, client, summarizer), | |
inputs=[memo_query_input], | |
outputs=memo_output | |
) | |
memo_add_course_btn.click( | |
fn=lambda name, url: add_course_to_memo(name, url, pine_index, embedding_model, client, summarizer), | |
inputs=[memo_course_name_input, memo_course_url_input], | |
outputs=memo_output | |
) | |
with gr.Tab("π Visualizer"): | |
with gr.Row(): | |
with gr.Column(scale=1): | |
visualizer_goal_input = gr.Textbox(label="Your Goal", placeholder="e.g., Become a Data Scientist", interactive=True) | |
visualizer_generate_btn = gr.Button("Generate Visual Roadmap") | |
with gr.Column(scale=2): | |
visualizer_output = gr.Plot(label="Visual Roadmap") | |
visualizer_generate_btn.click( | |
fn=lambda goal: generate_visual_roadmap(goal, visual_steps), | |
inputs=[visualizer_goal_input], | |
outputs=visualizer_output | |
) | |
def save_user_profile(nickname, weekly_goal): | |
user_id = nickname.lower().replace(" ", "_") | |
summary = f"User profile: {nickname}, goal: {weekly_goal}" | |
steps = [] # optional placeholder | |
courses = [] # optional placeholder | |
success = save_to_memory(user_id, "profile", summary, steps, courses) | |
if success: | |
user_id_state.value = user_id | |
return f"Profile for **{nickname}** saved! Weekly goal: **{weekly_goal}**" | |
else: | |
return "β Failed to save profile." | |
def load_user_profile(): | |
user_id = user_id_state.value | |
if not user_id: | |
return "", "", "β No user loaded." | |
profile_result = recall_from_memory(user_id, "profile") | |
if "β No saved plan" in profile_result: | |
return "", "", "β Profile not found in memory." | |
lines = profile_result.splitlines() | |
nickname_line = next((line for line in lines if "nickname" in line.lower()), "") | |
goal_line = next((line for line in lines if "goal" in line.lower()), "") | |
nickname = nickname_line.split(":")[-1].strip() if nickname_line else "" | |
weekly_goal = goal_line.split(":")[-1].strip() if goal_line else "" | |
return nickname, weekly_goal, "β Loaded profile from memory." | |
def generate_roadmap(goal, difficulty, pc, pine_index, client): | |
# This function would use the RAG system to generate a roadmap | |
# For now, return a placeholder | |
steps = [ | |
"Learn Python Basics", | |
"Understand Data Structures & Algorithms", | |
"Master SQL", | |
"Explore Machine Learning Fundamentals", | |
"Build a Portfolio Project", | |
"Apply for Jobs" | |
] | |
return render_text_roadmap(goal, steps) | |
import matplotlib.pyplot as plt | |
from modules.analysis import render_text_roadmap | |
def generate_visual_roadmap(goal, steps): | |
text_roadmap = render_text_roadmap(goal, steps, completed_tasks) | |
print(text_roadmap) # Optional: for debugging/logging | |
fig, ax = plt.subplots() | |
ax.barh(range(len(steps)), [1] * len(steps), tick_label=list(reversed(steps))) | |
ax.set_title(f"Visual Roadmap for {goal}") | |
ax.invert_yaxis() # So Step 1 is at the top | |
return fig | |
app.launch(debug=True) | |