Spaces:
Sleeping
Sleeping
Upload 4 files
Browse files- app.py +412 -0
- config.py +9 -0
- deployment_steps.md +74 -0
- requirements.txt +4 -0
app.py
ADDED
@@ -0,0 +1,412 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import datetime
|
3 |
+
import random
|
4 |
+
from collections import defaultdict
|
5 |
+
|
6 |
+
from utils.constants import TASK_DIFFICULTIES
|
7 |
+
from utils.data_helpers import smart_label_converter, clean_text, extract_actions_from_feedback
|
8 |
+
from utils.api_clients import initialize_api_clients
|
9 |
+
from utils.embedding_model import initialize_embedding_model
|
10 |
+
from utils.summarizer import initialize_summarizer
|
11 |
+
from modules.rag import load_docs, memo_rag_engine, batch_ingest_from_classcentral
|
12 |
+
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
|
13 |
+
from modules.analysis import analyze_linkedin, analyze_github, analyze_scraped_linkedin_profile, analyze_apify_dataset_ui
|
14 |
+
|
15 |
+
|
16 |
+
# ==== Global Variables ====
|
17 |
+
completed_tasks = set()
|
18 |
+
memo_data = []
|
19 |
+
visual_steps = []
|
20 |
+
|
21 |
+
# ==== API Clients & Models ====
|
22 |
+
pc, pine_index, APIFY_TOKEN, OPENAI_API_KEY, TAVILY_API_KEY, client = initialize_api_clients()
|
23 |
+
embedding_model = initialize_embedding_model()
|
24 |
+
summarizer = initialize_summarizer()
|
25 |
+
|
26 |
+
# ==== Gradio UI Components ====
|
27 |
+
class RoadmapUnlockManager:
|
28 |
+
def __init__(self):
|
29 |
+
self.unlocked = False
|
30 |
+
|
31 |
+
def unlock_roadmap(self):
|
32 |
+
self.unlocked = True
|
33 |
+
return gr.update(visible=True)
|
34 |
+
|
35 |
+
def get_roadmap_visibility(self):
|
36 |
+
return gr.update(visible=self.unlocked)
|
37 |
+
|
38 |
+
|
39 |
+
roadmap_unlock = RoadmapUnlockManager()
|
40 |
+
|
41 |
+
|
42 |
+
# === Roadmap Renderer ===
|
43 |
+
def render_text_roadmap(goal, steps):
|
44 |
+
global visual_steps
|
45 |
+
visual_steps = steps # ✅ Ensure this is set fresh each time
|
46 |
+
while len(steps) < 6:
|
47 |
+
steps.append("...")
|
48 |
+
def mark_done(text): return f"~~{text}~~" if text in completed_tasks else text
|
49 |
+
roadmap = [
|
50 |
+
f" 🏁 GOAL: {goal}",
|
51 |
+
" /\\",
|
52 |
+
" / \\",
|
53 |
+
f" / \\ • {mark_done(steps[5])}",
|
54 |
+
" / \\",
|
55 |
+
f" / \\ • {mark_done(steps[4])}",
|
56 |
+
" / \\",
|
57 |
+
f" / \\ • {mark_done(steps[3])}",
|
58 |
+
" / \\",
|
59 |
+
f" / \\ • {mark_done(steps[2])}",
|
60 |
+
" / \\",
|
61 |
+
f" / \\ • {mark_done(steps[1])}",
|
62 |
+
" / \\",
|
63 |
+
f" / \\ • {mark_done(steps[0])}",
|
64 |
+
" / \\",
|
65 |
+
" / \\",
|
66 |
+
" ____/ \\____"]
|
67 |
+
return "\\n".join(roadmap)
|
68 |
+
|
69 |
+
|
70 |
+
|
71 |
+
|
72 |
+
with gr.Blocks(css="""
|
73 |
+
@import url(\'https://fonts.googleapis.com/css2?family=Source+Sans+Pro&display=swap\');
|
74 |
+
|
75 |
+
body {
|
76 |
+
font-family: \'Source Sans Pro\', sans-serif;
|
77 |
+
background-color: #121212;
|
78 |
+
color: #f0f0f0;
|
79 |
+
}
|
80 |
+
|
81 |
+
#nickname-box {
|
82 |
+
max-width: 300px;
|
83 |
+
margin: 0 auto;
|
84 |
+
padding: 20px;
|
85 |
+
background-color: #1e1e1e;
|
86 |
+
border-radius: 12px;
|
87 |
+
box-shadow: 0px 0px 10px rgba(0,0,0,0.2);
|
88 |
+
}
|
89 |
+
|
90 |
+
#planner-card {
|
91 |
+
max-width: 720px;
|
92 |
+
margin: 0 auto;
|
93 |
+
padding: 28px;
|
94 |
+
background-color: #1e1e1e;
|
95 |
+
border-radius: 16px;
|
96 |
+
box-shadow: 0 0 12px rgba(0, 0, 0, 0.4);
|
97 |
+
}
|
98 |
+
|
99 |
+
#planner-card input,
|
100 |
+
#planner-card textarea,
|
101 |
+
#planner-card .gr-button {
|
102 |
+
font-size: 14px;
|
103 |
+
padding: 8px 12px;
|
104 |
+
border-radius: 8px;
|
105 |
+
}
|
106 |
+
|
107 |
+
#planner-card .gr-button {
|
108 |
+
background-color: #3a3aff;
|
109 |
+
color: white;
|
110 |
+
font-weight: bold;
|
111 |
+
}
|
112 |
+
|
113 |
+
#planner-card label {
|
114 |
+
font-weight: 600;
|
115 |
+
color: #f0f0f0;
|
116 |
+
}
|
117 |
+
|
118 |
+
#planner-card .gr-tab {
|
119 |
+
margin-top: 12px;
|
120 |
+
}
|
121 |
+
|
122 |
+
|
123 |
+
/* 🔗 Linky Tab Styling - Match Welcome Dark Mode */
|
124 |
+
|
125 |
+
#linky-tab {
|
126 |
+
background-color: #1e1e1e !important;
|
127 |
+
color: #f0f0f0 !important;
|
128 |
+
padding: 24px;
|
129 |
+
border-radius: 16px;
|
130 |
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
|
131 |
+
}
|
132 |
+
|
133 |
+
/* Fix outer wrappers Gradio uses */
|
134 |
+
#linky-tab .gr-block,
|
135 |
+
#linky-tab .gr-column,
|
136 |
+
#linky-tab .gr-panel {
|
137 |
+
background-color: transparent !important;
|
138 |
+
color: inherit;
|
139 |
+
box-shadow: none;}
|
140 |
+
|
141 |
+
/* Override inputs + textareas inside dark tab */
|
142 |
+
#linky-tab input,
|
143 |
+
#linky-tab textarea {
|
144 |
+
background-color: #2c2c2c !important;
|
145 |
+
color: #ffffff !important;
|
146 |
+
border: 1px solid #444 !important;
|
147 |
+
border-radius: 6px;}
|
148 |
+
|
149 |
+
/* Fix submit button look */
|
150 |
+
#linky-tab .gr-button {
|
151 |
+
background-color: #4444aa !important;
|
152 |
+
color: #fff !important;
|
153 |
+
border-radius: 6px;}
|
154 |
+
|
155 |
+
#dds-logo img {
|
156 |
+
max-width: 200px;
|
157 |
+
display: block;
|
158 |
+
margin: 0 auto 15px;
|
159 |
+
}
|
160 |
+
|
161 |
+
/* Shared Card Styling (like Welcome tab) */
|
162 |
+
#user-card {
|
163 |
+
background-color: #ffffff;
|
164 |
+
border: 1px solid #dddddd;
|
165 |
+
border-radius: 12px;
|
166 |
+
padding: 24px;
|
167 |
+
margin-top: 20px;
|
168 |
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
169 |
+
color: #1a1a1a;
|
170 |
+
}
|
171 |
+
|
172 |
+
#user-card input,
|
173 |
+
#user-card textarea {
|
174 |
+
background-color: #f5f5f5 !important;
|
175 |
+
color: #111111 !important;
|
176 |
+
border: 1px solid #ccc;
|
177 |
+
border-radius: 6px;
|
178 |
+
padding: 10px;
|
179 |
+
}
|
180 |
+
|
181 |
+
#user-card label {
|
182 |
+
color: #333333;
|
183 |
+
}
|
184 |
+
|
185 |
+
/* Responsive Tweaks */
|
186 |
+
@media (max-width: 768px) {
|
187 |
+
.gr-row {
|
188 |
+
flex-direction: column !important;
|
189 |
+
}
|
190 |
+
|
191 |
+
#user-card {
|
192 |
+
margin-top: 20px;
|
193 |
+
}
|
194 |
+
}
|
195 |
+
""") as app:
|
196 |
+
user_id_state = gr.State()
|
197 |
+
roadmap_unlock = RoadmapUnlockManager()
|
198 |
+
start_date = gr.Textbox(label="📅 Start Date", value=str(datetime.date.today()))
|
199 |
+
|
200 |
+
with gr.Tabs():
|
201 |
+
with gr.Tab("✨ Welcome"):
|
202 |
+
with gr.Row(equal_height=True):
|
203 |
+
# LEFT: Intro
|
204 |
+
with gr.Column(scale=2):
|
205 |
+
gr.Markdown("""
|
206 |
+
# 👋 Welcome to Career Buddy!
|
207 |
+
**Your AI-powered career planner** for LinkedIn, GitHub, and goal-tracking.**
|
208 |
+
If you enjoy this project and want to help me beat OpenAI costs; support me below
|
209 |
+
""")
|
210 |
+
|
211 |
+
gr.HTML("""<a href="https://ko-fi.com/wishingonstars" target="_blank"><img src="https://unfetteredpatterns.blog/wp-content/uploads/2025/05/support.png" alt="Support Me on Ko-fi" style="width: 150px;"></a>""")
|
212 |
+
|
213 |
+
gr.Markdown("""
|
214 |
+
### 🚀 Get Started
|
215 |
+
1. **Enter your nickname** to personalize your journey.
|
216 |
+
2. **Set your weekly goal** to stay on track.
|
217 |
+
3. **Explore the tabs** for LinkedIn/GitHub analysis, smart planning, and more!
|
218 |
+
""")
|
219 |
+
|
220 |
+
# RIGHT: User Input
|
221 |
+
with gr.Column(scale=1, elem_id="user-card"):
|
222 |
+
gr.Markdown("## Your Journey Starts Here")
|
223 |
+
nickname_input = gr.Textbox(label="Enter your Nickname", placeholder="e.g., DataScientistPro", interactive=True)
|
224 |
+
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)
|
225 |
+
with gr.Row():
|
226 |
+
save_btn = gr.Button("Save Profile")
|
227 |
+
load_btn = gr.Button("Load Profile")
|
228 |
+
|
229 |
+
gr.Markdown("### Your Progress")
|
230 |
+
progress_output = gr.Markdown("", elem_id="progress-output")
|
231 |
+
|
232 |
+
save_btn.click(
|
233 |
+
fn=lambda nickname, goal: save_user_profile(nickname, goal),
|
234 |
+
inputs=[nickname_input, weekly_goal_input],
|
235 |
+
outputs=progress_output
|
236 |
+
)
|
237 |
+
load_btn.click(
|
238 |
+
fn=lambda: load_user_profile(),
|
239 |
+
inputs=[],
|
240 |
+
outputs=[nickname_input, weekly_goal_input, progress_output]
|
241 |
+
)
|
242 |
+
|
243 |
+
with gr.Tab("🔗 Linky (LinkedIn Analyzer)", elem_id="linky-tab"):
|
244 |
+
with gr.Row():
|
245 |
+
with gr.Column(scale=1):
|
246 |
+
linkedin_url_input = gr.Textbox(label="LinkedIn Profile URL", placeholder="Paste your LinkedIn profile URL here", interactive=True)
|
247 |
+
analyze_linkedin_btn = gr.Button("Analyze LinkedIn Profile")
|
248 |
+
gr.Markdown("### Or analyze a local Apify dataset CSV")
|
249 |
+
apify_dataset_btn = gr.Button("Analyze Apify Dataset (CSV)")
|
250 |
+
with gr.Column(scale=2):
|
251 |
+
linkedin_analysis_output = gr.Markdown("", label="LinkedIn Analysis Results")
|
252 |
+
|
253 |
+
analyze_linkedin_btn.click(
|
254 |
+
fn=fetch_and_analyze_linkedin,
|
255 |
+
inputs=[linkedin_url_input],
|
256 |
+
outputs=linkedin_analysis_output
|
257 |
+
)
|
258 |
+
apify_dataset_btn.click(
|
259 |
+
fn=analyze_apify_dataset_ui,
|
260 |
+
inputs=[],
|
261 |
+
outputs=linkedin_analysis_output
|
262 |
+
)
|
263 |
+
|
264 |
+
with gr.Tab("🐙 GitGuru (GitHub Reviewer)"):
|
265 |
+
with gr.Row():
|
266 |
+
with gr.Column(scale=1):
|
267 |
+
github_readme_input = gr.Textbox(label="GitHub README Content", placeholder="Paste your main GitHub README content here", lines=10, interactive=True)
|
268 |
+
analyze_github_btn = gr.Button("Analyze GitHub README")
|
269 |
+
with gr.Column(scale=2):
|
270 |
+
github_analysis_output = gr.Markdown("", label="GitHub Analysis Results")
|
271 |
+
|
272 |
+
analyze_github_btn.click(
|
273 |
+
fn=analyze_github,
|
274 |
+
inputs=[github_readme_input],
|
275 |
+
outputs=github_analysis_output
|
276 |
+
)
|
277 |
+
|
278 |
+
with gr.Tab("🧠 Smart Planner"):
|
279 |
+
with gr.Row():
|
280 |
+
with gr.Column(scale=1):
|
281 |
+
planner_goal_input = gr.Textbox(label="Your Goal", placeholder="e.g., Become a Data Scientist", interactive=True)
|
282 |
+
planner_difficulty_input = gr.Dropdown(label="Difficulty", choices=TASK_DIFFICULTIES, value="Medium", interactive=True)
|
283 |
+
planner_generate_btn = gr.Button("Generate Roadmap")
|
284 |
+
with gr.Column(scale=2):
|
285 |
+
roadmap_output = gr.Markdown("", label="Career Roadmap")
|
286 |
+
|
287 |
+
planner_generate_btn.click(
|
288 |
+
fn=lambda goal, difficulty: generate_roadmap(goal, difficulty, pc, pine_index, client),
|
289 |
+
inputs=[planner_goal_input, planner_difficulty_input],
|
290 |
+
outputs=roadmap_output
|
291 |
+
)
|
292 |
+
|
293 |
+
with gr.Tab("🎯 Task Tracker"):
|
294 |
+
with gr.Row():
|
295 |
+
with gr.Column(scale=1):
|
296 |
+
task_name_input = gr.Textbox(label="Task Name", placeholder="e.g., Complete Python course", interactive=True)
|
297 |
+
task_type_input = gr.Dropdown(label="Task Type", choices=["Learning", "Networking", "Project", "Application"], value="Learning", interactive=True)
|
298 |
+
task_add_btn = gr.Button("Add Task")
|
299 |
+
|
300 |
+
gr.Markdown("### Mark Task Steps Completed")
|
301 |
+
task_step_input = gr.Textbox(label="Step to Mark Completed", placeholder="e.g., Chapter 1 of Python course", interactive=True)
|
302 |
+
task_mark_completed_btn = gr.Button("Mark Step Completed")
|
303 |
+
|
304 |
+
gr.Markdown("### Rewards")
|
305 |
+
reward_amount_input = gr.Number(label="Reward Amount", value=10, interactive=True)
|
306 |
+
reward_claim_btn = gr.Button("Claim Reward")
|
307 |
+
|
308 |
+
reset_weekly_btn = gr.Button("Reset Weekly Data")
|
309 |
+
|
310 |
+
with gr.Column(scale=2):
|
311 |
+
tasks_display = gr.Markdown("", label="Your Tasks")
|
312 |
+
progress_bar = gr.HTML("", label="Weekly Progress")
|
313 |
+
rewards_display = gr.Markdown("", label="Your Rewards")
|
314 |
+
|
315 |
+
task_add_btn.click(
|
316 |
+
fn=lambda user_id, task_name, task_type: add_task(user_id, task_name, task_type, tasks_display, progress_bar, rewards_display),
|
317 |
+
inputs=[user_id_state, task_name_input, task_type_input],
|
318 |
+
outputs=[tasks_display, progress_bar, rewards_display]
|
319 |
+
)
|
320 |
+
|
321 |
+
task_mark_completed_btn.click(
|
322 |
+
fn=lambda user_id, step: mark_step_completed(user_id, step, tasks_display, progress_bar, rewards_display),
|
323 |
+
inputs=[user_id_state, task_step_input],
|
324 |
+
outputs=[tasks_display, progress_bar, rewards_display]
|
325 |
+
)
|
326 |
+
|
327 |
+
reward_claim_btn.click(
|
328 |
+
fn=lambda user_id, amount: claim_reward(user_id, amount, rewards_display),
|
329 |
+
inputs=[user_id_state, reward_amount_input],
|
330 |
+
outputs=rewards_display
|
331 |
+
)
|
332 |
+
|
333 |
+
reset_weekly_btn.click(
|
334 |
+
fn=lambda user_id: reset_weekly_data(user_id, tasks_display, progress_bar, rewards_display),
|
335 |
+
inputs=[user_id_state],
|
336 |
+
outputs=[tasks_display, progress_bar, rewards_display]
|
337 |
+
)
|
338 |
+
|
339 |
+
with gr.Tab("📚 Memo (Course Recommender)"):
|
340 |
+
with gr.Row():
|
341 |
+
with gr.Column(scale=1):
|
342 |
+
memo_query_input = gr.Textbox(label="Ask about a course or topic", placeholder="e.g., Best Python courses for data science", interactive=True)
|
343 |
+
memo_search_btn = gr.Button("Search Courses")
|
344 |
+
gr.Markdown("### Add Course to Memo")
|
345 |
+
memo_course_name_input = gr.Textbox(label="Course Name", interactive=True)
|
346 |
+
memo_course_url_input = gr.Textbox(label="Course URL", interactive=True)
|
347 |
+
memo_add_course_btn = gr.Button("Add Course")
|
348 |
+
with gr.Column(scale=2):
|
349 |
+
memo_output = gr.Markdown("", label="Course Recommendations")
|
350 |
+
|
351 |
+
memo_search_btn.click(
|
352 |
+
fn=lambda query: memo_rag_engine(query, pine_index, embedding_model, client, summarizer),
|
353 |
+
inputs=[memo_query_input],
|
354 |
+
outputs=memo_output
|
355 |
+
)
|
356 |
+
memo_add_course_btn.click(
|
357 |
+
fn=lambda name, url: add_course_to_memo(name, url, pine_index, embedding_model, client, summarizer),
|
358 |
+
inputs=[memo_course_name_input, memo_course_url_input],
|
359 |
+
outputs=memo_output
|
360 |
+
)
|
361 |
+
|
362 |
+
with gr.Tab("📊 Visualizer"):
|
363 |
+
with gr.Row():
|
364 |
+
with gr.Column(scale=1):
|
365 |
+
visualizer_goal_input = gr.Textbox(label="Your Goal", placeholder="e.g., Become a Data Scientist", interactive=True)
|
366 |
+
visualizer_generate_btn = gr.Button("Generate Visual Roadmap")
|
367 |
+
with gr.Column(scale=2):
|
368 |
+
visualizer_output = gr.Plot(label="Visual Roadmap")
|
369 |
+
|
370 |
+
visualizer_generate_btn.click(
|
371 |
+
fn=lambda goal: generate_visual_roadmap(goal, visual_steps),
|
372 |
+
inputs=[visualizer_goal_input],
|
373 |
+
outputs=visualizer_output
|
374 |
+
)
|
375 |
+
|
376 |
+
|
377 |
+
def save_user_profile(nickname, weekly_goal):
|
378 |
+
user_id = nickname.lower().replace(" ", "_")
|
379 |
+
user_id_state.value = user_id
|
380 |
+
# In a real app, you\\'d save this to a database
|
381 |
+
return f"Profile for **{nickname}** saved! Weekly goal: **{weekly_goal}**"
|
382 |
+
|
383 |
+
def load_user_profile():
|
384 |
+
# In a real app, you\\'d load this from a database
|
385 |
+
# For now, just return some dummy data
|
386 |
+
return "DataScientistPro", "Apply to 5 jobs, finish a Python course", "Loaded dummy profile."
|
387 |
+
|
388 |
+
def generate_roadmap(goal, difficulty, pc, pine_index, client):
|
389 |
+
# This function would use the RAG system to generate a roadmap
|
390 |
+
# For now, return a placeholder
|
391 |
+
steps = [
|
392 |
+
"Learn Python Basics",
|
393 |
+
"Understand Data Structures & Algorithms",
|
394 |
+
"Master SQL",
|
395 |
+
"Explore Machine Learning Fundamentals",
|
396 |
+
"Build a Portfolio Project",
|
397 |
+
"Apply for Jobs"
|
398 |
+
]
|
399 |
+
return render_text_roadmap(goal, steps)
|
400 |
+
|
401 |
+
def generate_visual_roadmap(goal, steps):
|
402 |
+
# This function would generate a visual roadmap using matplotlib or similar
|
403 |
+
# For now, return a placeholder plot
|
404 |
+
import matplotlib.pyplot as plt
|
405 |
+
fig, ax = plt.subplots()
|
406 |
+
ax.barh(steps, [1]*len(steps))
|
407 |
+
ax.set_title(f"Visual Roadmap for {goal}")
|
408 |
+
return fig
|
409 |
+
|
410 |
+
|
411 |
+
app.launch(debug=True, enable_queue=True)
|
412 |
+
|
config.py
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
class Config:
|
4 |
+
APIFY_TOKEN = os.getenv("APIFY_TOKEN")
|
5 |
+
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
6 |
+
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY")
|
7 |
+
|
8 |
+
config = Config()
|
9 |
+
|
deployment_steps.md
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Hugging Face Space Deployment Steps for Career Buddy
|
2 |
+
|
3 |
+
This document outlines the steps to deploy the Career Buddy application to Hugging Face Spaces.
|
4 |
+
|
5 |
+
## 1. Prepare your Environment
|
6 |
+
|
7 |
+
Ensure you have the following installed:
|
8 |
+
- Git LFS (for large files)
|
9 |
+
- Hugging Face Hub library (`pip install huggingface_hub`)
|
10 |
+
|
11 |
+
## 2. Authenticate with Hugging Face
|
12 |
+
|
13 |
+
Run the following command in your terminal and follow the prompts to log in:
|
14 |
+
|
15 |
+
```bash
|
16 |
+
huggingface-cli login
|
17 |
+
```
|
18 |
+
|
19 |
+
## 3. Create a New Hugging Face Space
|
20 |
+
|
21 |
+
Go to [Hugging Face Spaces](https://huggingface.co/spaces) and create a new Space. Choose:
|
22 |
+
- **Space SDK**: Gradio
|
23 |
+
- **Hardware**: Recommended to use a GPU instance for better performance with LLMs and embedding models.
|
24 |
+
- **Visibility**: Public or Private, as per your preference.
|
25 |
+
|
26 |
+
## 4. Clone your Space Repository
|
27 |
+
|
28 |
+
After creating the Space, you will be redirected to its page. Click on the "Files" tab and then "Clone repository" to get the Git clone URL. Clone it to your local machine:
|
29 |
+
|
30 |
+
```bash
|
31 |
+
git clone https://huggingface.co/spaces/<your-username>/<your-space-name>
|
32 |
+
cd <your-space-name>
|
33 |
+
```
|
34 |
+
|
35 |
+
## 5. Copy the Updated Codebase
|
36 |
+
|
37 |
+
Copy all the refactored files and directories (`app.py`, `modules/`, `utils/`, `config.py`, `requirements.txt`, `data/`) into your cloned Space repository.
|
38 |
+
|
39 |
+
```bash
|
40 |
+
cp -r /path/to/your/updated/career_buddy/* ./
|
41 |
+
```
|
42 |
+
|
43 |
+
## 6. Set Environment Variables
|
44 |
+
|
45 |
+
Hugging Face Spaces allows you to set environment variables securely. Go to your Space settings, navigate to "Repository secrets", and add the following:
|
46 |
+
|
47 |
+
- `OPENAI_API_KEY`
|
48 |
+
- `APIFY_TOKEN`
|
49 |
+
- `TAVILY_API_KEY`
|
50 |
+
|
51 |
+
## 7. Install Dependencies
|
52 |
+
|
53 |
+
Ensure your `requirements.txt` file is up-to-date with all necessary Python packages. The provided `requirements.txt` should be sufficient. Hugging Face Spaces will automatically install these dependencies when the Space builds.
|
54 |
+
|
55 |
+
## 8. Push to Hugging Face Space
|
56 |
+
|
57 |
+
Commit your changes and push them to the Hugging Face Space repository:
|
58 |
+
|
59 |
+
```bash
|
60 |
+
git add .
|
61 |
+
git commit -m "Initial deployment of refactored Career Buddy"
|
62 |
+
git push
|
63 |
+
```
|
64 |
+
|
65 |
+
Your Space will then start building. You can monitor the build logs in the "Logs" tab of your Space page. Once the build is successful, your Career Buddy application will be live!
|
66 |
+
|
67 |
+
## 9. Data Persistence (Optional but Recommended)
|
68 |
+
|
69 |
+
For persistent data (like `memo_data` or user profiles), consider integrating with external databases (e.g., Firebase, PostgreSQL) or using Hugging Face Datasets for larger datasets. The current implementation uses local files for RAG data, which will be part of the Space's persistent storage if committed to the repository.
|
70 |
+
|
71 |
+
## 10. Continuous Integration/Continuous Deployment (CI/CD)
|
72 |
+
|
73 |
+
For future updates, you can set up CI/CD pipelines (e.g., GitHub Actions) to automatically deploy changes to your Hugging Face Space whenever you push to your main branch.
|
74 |
+
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
matplotlib
|
3 |
+
requests-cache
|
4 |
+
|