rivapereira123 commited on
Commit
c593899
·
verified ·
1 Parent(s): d0f848a

Upload 4 files

Browse files
Files changed (4) hide show
  1. app.py +412 -0
  2. config.py +9 -0
  3. deployment_steps.md +74 -0
  4. 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
+