rivapereira123 commited on
Commit
4c9c33d
Β·
verified Β·
1 Parent(s): 9d151bd

Upload app_fully_safe.py

Browse files
Files changed (1) hide show
  1. app_fully_safe.py +378 -0
app_fully_safe.py ADDED
@@ -0,0 +1,378 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 utils.constants import course_suggestions
12
+ from modules.rag import load_docs, memo_rag_engine, batch_ingest_from_classcentral
13
+ 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
14
+ from modules.analysis import analyze_linkedin, analyze_github, analyze_scraped_linkedin_profile, analyze_apify_dataset_ui
15
+ from modules.analysis import fetch_and_analyze_linkedin
16
+ import textwrap
17
+
18
+
19
+ # ==== Global Variables ====
20
+ completed_tasks = set()
21
+ memo_data = []
22
+ visual_steps = []
23
+
24
+ # ==== API Clients & Models ====
25
+ pc, pine_index, APIFY_TOKEN, OPENAI_API_KEY, TAVILY_API_KEY, client = initialize_api_clients()
26
+ embedding_model = initialize_embedding_model()
27
+ summarizer = initialize_summarizer()
28
+
29
+ # ==== Gradio UI Components ====
30
+ class RoadmapUnlockManager:
31
+ def __init__(self):
32
+ self.unlocked = False
33
+
34
+ def unlock_roadmap(self):
35
+ self.unlocked = True
36
+ return gr.update(visible=True)
37
+
38
+ def get_roadmap_visibility(self):
39
+ return gr.update(visible=self.unlocked)
40
+
41
+
42
+ roadmap_unlock = RoadmapUnlockManager()
43
+
44
+
45
+ # === Roadmap Renderer ===
46
+ def render_text_roadmap(goal, steps):
47
+ global visual_steps
48
+ visual_steps = steps # βœ… Ensure this is set fresh each time
49
+ while len(steps) < 6:
50
+ steps.append("...")
51
+ def mark_done(text): return f"~~{text}~~" if text in completed_tasks else text
52
+ roadmap = [
53
+ f" 🏁 GOAL: {goal}",
54
+ " /\\",
55
+ " / \\",
56
+ f" / \\ β€’ {mark_done(steps[5])}",
57
+ " / \\",
58
+ f" / \\ β€’ {mark_done(steps[4])}",
59
+ " / \\",
60
+ f" / \\ β€’ {mark_done(steps[3])}",
61
+ " / \\",
62
+ f" / \\ β€’ {mark_done(steps[2])}",
63
+ " / \\",
64
+ f" / \\ β€’ {mark_done(steps[1])}",
65
+ " / \\",
66
+ f" / \\ β€’ {mark_done(steps[0])}",
67
+ " / \\",
68
+ " / \\",
69
+ " ____/ \\____"]
70
+ return "\\n".join(roadmap)
71
+
72
+
73
+
74
+ def recall_from_memory(user_id, goal):
75
+ try:
76
+ query = user_id + ":" + goal.replace(" ", "_")
77
+ result = pine_index.fetch([query]) # βœ… returns a FetchResponse object
78
+
79
+ if query not in result.vectors:
80
+ return "❌ No saved plan found for this goal."
81
+
82
+ metadata = result.vectors[query].get("metadata", {})
83
+ steps = metadata.get("steps", [])
84
+ steps = [smart_label_converter(s) for s in steps if isinstance(s, str) and len(s.strip()) > 1]
85
+ summary = metadata.get("summary", "")
86
+ courses = metadata.get("courses", [])
87
+ course_section = ""
88
+
89
+ diagram = render_text_roadmap(goal, steps)
90
+
91
+ if courses:
92
+ course_section = "\n\n### πŸ“š Recommended Courses\n" + "\n".join([f"- [{c['name']}]({c['url']})" for c in courses if 'name' in c and 'url' in c])
93
+
94
+ return f"""### πŸ” Recalled Plan for {goal}
95
+
96
+ import textwrap
97
+
98
+ def generate_smart_plan(user_id, start_date_str, goal):
99
+ import datetime
100
+ import difflib
101
+ import re
102
+
103
+ start_date = datetime.datetime.strptime(start_date_str, "%Y-%m-%d").date()
104
+
105
+ if not user_id:
106
+ return "❌ Please enter a nickname in the Welcome tab.", "", "πŸ“… Week 1"
107
+
108
+ user_key = user_id.strip().lower()
109
+ goal_key = goal.lower().strip()
110
+
111
+ if goal_key not in course_suggestions:
112
+ close_matches = difflib.get_close_matches(goal_key, course_suggestions.keys(), n=1, cutoff=0.6)
113
+ if close_matches:
114
+ goal_key = close_matches[0]
115
+
116
+ plan_markdown = f"""### Plan for {goal}
117
+
118
+ {diagram}
119
+
120
+ {summary}{course_section}
121
+
122
+ _Source: See planner source_"""
123
+
124
+ plan_source = "Loaded from memory"
125
+ save_to_memory(user_id, goal, summary, steps, courses)
126
+
127
+ # 2️⃣ Try Tavilly fallback
128
+ if not steps:
129
+ try:
130
+ print("πŸ§ͺ Trying Tavilly fallback for:", goal_key)
131
+ result = call_tavilly_rag(user_id, goal_key)
132
+ print("βœ… Tavilly returned something:", result)
133
+ tav_plan = re.sub(r'(Create a weekly roadmap.*?)\1+', r'\1', result[0], flags=re.DOTALL)
134
+ tav_steps = [smart_label_converter(s) for s in result[2] if isinstance(s, str) and len(s.strip()) > 1]
135
+ if tav_steps:
136
+ steps = tav_steps
137
+ diagram = render_text_roadmap(goal, steps)
138
+ summary = summarizer(f"Create a weekly roadmap for {goal}.", max_new_tokens=300, do_sample=False)[0]["generated_text"]
139
+ courses = get_courses_for_goal(goal_key)
140
+ course_section = "\n\n### πŸ“š Recommended Courses\n" + "\n".join([f"- [{name}]({url})" for name, url in courses]) if courses else ""
141
+ plan_markdown = f"""### Plan for {goal}
142
+
143
+ {diagram}
144
+
145
+ {summary}{course_section}
146
+
147
+ _Source: See planner source_"""
148
+ plan_source = "Loaded from memory"
149
+
150
+ for step in steps:
151
+ if isinstance(step, str) and len(step.strip()) > 1:
152
+ add_task(user_id, task=step, duration=2, difficulty="Moderate", tag=None, source="career")
153
+
154
+ print("βœ… Returning", len(steps), "steps for goal:", goal)
155
+ return plan_markdown, gr.update(choices=steps, value=[]), "πŸ“… Week 1"
156
+
157
+
158
+
159
+ with gr.Blocks(theme="NoCrypt/[email protected]",css="theme.css") as app:
160
+ user_id_state = gr.State()
161
+ roadmap_unlock = RoadmapUnlockManager()
162
+ start_date = gr.Textbox(label="πŸ“… Start Date", value=str(datetime.date.today()))
163
+
164
+ with gr.Tabs():
165
+ with gr.Tab("✨ Welcome"):
166
+ with gr.Row(equal_height=True):
167
+ # LEFT: Intro
168
+ with gr.Column(scale=2):
169
+ gr.Markdown("""
170
+ # πŸ‘‹ Welcome to Career Buddy!
171
+ **Your AI-powered career planner** for LinkedIn, GitHub, and goal-tracking.**
172
+ If you enjoy this project and want to help me beat OpenAI costs; support me below
173
+ """)
174
+
175
+ gr.HTML('''<a href="https://ko-fi.com/wishingonstars" target="_blank"><img src="https://unfetteredpatterns.blog/wp-content/uploads/2025/05/support_me_on_kofi_badge_dark.webp" style="height: 72px; padding: 4px;" alt="Support me on Ko-fi" /></a>''')
176
+
177
+ gr.Markdown("""
178
+ ### πŸš€ Get Started
179
+ 1. **Enter your nickname** to personalize your journey.
180
+ 2. **Set your weekly goal** to stay on track.
181
+ 3. **Explore the tabs** for LinkedIn/GitHub analysis, smart planning, and more!
182
+ """)
183
+
184
+ # RIGHT: User Input
185
+ with gr.Column(scale=1, elem_id="user-card"):
186
+ gr.Markdown("## Your Journey Starts Here")
187
+ nickname_input = gr.Textbox(label="Enter your Nickname", placeholder="e.g., DataScientistPro", interactive=True)
188
+ 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)
189
+ with gr.Row():
190
+ save_btn = gr.Button("Save Profile")
191
+ load_btn = gr.Button("Load Profile")
192
+
193
+ gr.Markdown("### Your Progress")
194
+ progress_output = gr.Markdown("", elem_id="progress-output")
195
+
196
+ save_btn.click(fn=lambda nickname, goal: (save_user_profile(nickname, goal), nickname.strip().lower().replace(' ', '_')),inputs=[nickname_input, weekly_goal_input],outputs=[progress_output, user_id_state])
197
+
198
+ load_btn.click(
199
+ fn=lambda: load_user_profile(),
200
+ inputs=[],
201
+ outputs=[nickname_input, weekly_goal_input, progress_output, user_id_state]
202
+ )
203
+
204
+ with gr.Tab("πŸ”— Linky (LinkedIn Analyzer)", elem_id="linky-tab"):
205
+ with gr.Row():
206
+ with gr.Column(scale=1):
207
+ linkedin_url_input = gr.Textbox(label="LinkedIn Profile URL", placeholder="Paste your LinkedIn profile URL here", interactive=True)
208
+ analyze_linkedin_btn = gr.Button("Analyze LinkedIn Profile")
209
+ gr.Markdown("### Or analyze a local Apify dataset CSV")
210
+ apify_dataset_btn = gr.Button("Analyze Apify Dataset (CSV)")
211
+ with gr.Column(scale=2):
212
+ linkedin_analysis_output = gr.Markdown("", label="LinkedIn Analysis Results")
213
+
214
+ analyze_linkedin_btn.click(
215
+ fn=fetch_and_analyze_linkedin,
216
+ inputs=[linkedin_url_input],
217
+ outputs=linkedin_analysis_output
218
+ )
219
+ apify_dataset_btn.click(
220
+ fn=analyze_apify_dataset_ui,
221
+ inputs=[],
222
+ outputs=linkedin_analysis_output
223
+ )
224
+
225
+ with gr.Tab("πŸ™ GitGuru (GitHub Reviewer)", elem_id="gitguru-tab"):
226
+ with gr.Row():
227
+ with gr.Column(scale=1):
228
+ github_readme_input = gr.Textbox(label="GitHub README Content", placeholder="Paste your main GitHub README content here", lines=10, interactive=True)
229
+ analyze_github_btn = gr.Button("Analyze GitHub README")
230
+ with gr.Column(scale=2):
231
+ github_analysis_output = gr.Markdown("", label="GitHub Analysis Results")
232
+
233
+ analyze_github_btn.click(
234
+ fn=analyze_github,
235
+ inputs=[github_readme_input],
236
+ outputs=github_analysis_output
237
+ )
238
+
239
+ with gr.Tab("🧠 Smart Planner", elem_id="planner-card"):
240
+ with gr.Row():
241
+ with gr.Column(scale=1):
242
+ planner_goal_input = gr.Textbox(label="Your Goal", placeholder="e.g., Become a Data Scientist", interactive=True)
243
+ planner_difficulty_input = gr.Dropdown(label="Difficulty", choices=TASK_DIFFICULTIES, value="Moderate", interactive=True)
244
+ planner_generate_btn = gr.Button("Generate Roadmap")
245
+ with gr.Column(scale=2):
246
+ roadmap_output = gr.Markdown("", label="Career Roadmap")
247
+ planner_step_dropdown = gr.Dropdown(label="Planned Steps", choices=[], multiselect=True, visible=False)
248
+ planner_week_marker = gr.Textbox(label="Current Week", value="πŸ“… Week 1", visible=False)
249
+
250
+
251
+ planner_generate_btn.click(
252
+ fn=generate_smart_plan,
253
+ inputs=[user_id_state, start_date, planner_goal_input],
254
+ outputs=[roadmap_output, planner_step_dropdown, planner_week_marker])
255
+
256
+
257
+ with gr.Tab("🎯 Task Tracker", elem_id="gitguru-tab"):
258
+ with gr.Row():
259
+ with gr.Column(scale=1):
260
+ task_name_input = gr.Textbox(label="Task Name", placeholder="e.g., Complete Python course", interactive=True)
261
+ task_type_input = gr.Dropdown(label="Task Type", choices=["Learning", "Networking", "Project", "Application"], value="Learning", interactive=True)
262
+ task_add_btn = gr.Button("Add Task")
263
+
264
+ gr.Markdown("### Mark Task Steps Completed")
265
+ task_step_input = gr.Textbox(label="Step to Mark Completed", placeholder="e.g., Chapter 1 of Python course", interactive=True)
266
+ task_mark_completed_btn = gr.Button("Mark Step Completed")
267
+
268
+ gr.Markdown("### Rewards")
269
+ reward_amount_input = gr.Number(label="Reward Amount", value=10, interactive=True)
270
+ reward_claim_btn = gr.Button("Claim Reward")
271
+
272
+ reset_weekly_btn = gr.Button("Reset Weekly Data")
273
+
274
+ with gr.Column(scale=2):
275
+ tasks_display = gr.Markdown("", label="Your Tasks")
276
+ progress_bar = gr.HTML("", label="Weekly Progress")
277
+ rewards_display = gr.Markdown("", label="Your Rewards")
278
+
279
+ task_add_btn.click(
280
+ fn=lambda user_id, task_name, task_type: add_task(user_id, task_name, task_type),
281
+ outputs=[tasks_display, progress_bar, rewards_display]
282
+
283
+ )
284
+
285
+ task_mark_completed_btn.click(
286
+ fn=lambda user_id, step: mark_step_completed(user_id, step, tasks_display, progress_bar, rewards_display),
287
+ inputs=[user_id_state, task_step_input],
288
+ outputs=[tasks_display, progress_bar, rewards_display]
289
+ )
290
+
291
+ reward_claim_btn.click(
292
+ fn=lambda user_id, amount: claim_reward(user_id, amount, rewards_display),
293
+ inputs=[user_id_state, reward_amount_input],
294
+ outputs=rewards_display
295
+ )
296
+
297
+ reset_weekly_btn.click(
298
+ fn=lambda user_id: reset_weekly_data(user_id, tasks_display, progress_bar, rewards_display),
299
+ inputs=[user_id_state],
300
+ outputs=[tasks_display, progress_bar, rewards_display]
301
+ )
302
+
303
+ with gr.Tab("πŸ“š Memo (Course Recommender)", elem_id="gitguru-tab"):
304
+ with gr.Row():
305
+ with gr.Column(scale=1):
306
+ memo_query_input = gr.Textbox(label="Ask about a course or topic", placeholder="e.g., Best Python courses for data science", interactive=True)
307
+ memo_search_btn = gr.Button("Search Courses")
308
+ gr.Markdown("### Add Course to Memo")
309
+ memo_course_name_input = gr.Textbox(label="Course Name", interactive=True)
310
+ memo_course_url_input = gr.Textbox(label="Course URL", interactive=True)
311
+ memo_add_course_btn = gr.Button("Add Course")
312
+ with gr.Column(scale=2):
313
+ memo_output = gr.Markdown("", label="Course Recommendations")
314
+
315
+ memo_search_btn.click(
316
+ fn=lambda query: memo_rag_engine(query, pine_index, embedding_model, client, summarizer),
317
+ inputs=[memo_query_input],
318
+ outputs=memo_output
319
+ )
320
+ memo_add_course_btn.click(
321
+ fn=lambda name, url: add_course_to_memo(name, url, pine_index, embedding_model, client, summarizer),
322
+ inputs=[memo_course_name_input, memo_course_url_input],
323
+ outputs=memo_output
324
+ )
325
+
326
+ with gr.Tab("πŸ“Š Visualizer", elem_id="gitguru-tab"):
327
+ with gr.Row():
328
+ with gr.Column(scale=1):
329
+ visualizer_goal_input = gr.Textbox(label="Your Goal", placeholder="e.g., Become a Data Scientist", interactive=True)
330
+ visualizer_generate_btn = gr.Button("Generate Visual Roadmap")
331
+ with gr.Column(scale=2):
332
+ visualizer_output = gr.Plot(label="Visual Roadmap")
333
+
334
+ visualizer_generate_btn.click(
335
+ fn=lambda goal: generate_visual_roadmap(goal, visual_steps),
336
+ inputs=[visualizer_goal_input],
337
+ outputs=visualizer_output
338
+ )
339
+
340
+
341
+ def save_user_profile(nickname, weekly_goal):
342
+ user_id = nickname.lower().replace(" ", "_")
343
+ user_id_state.value = user_id
344
+ # In a real app, you\\'d save this to a database
345
+ return f"Profile for **{nickname}** saved! Weekly goal: **{weekly_goal}**"
346
+
347
+ def load_user_profile():
348
+ # In a real app, you\\'d load this from a database
349
+ # For now, just return some dummy data
350
+ return "DataScientistPro", "Apply to 5 jobs, finish a Python course", "Loaded dummy profile."
351
+
352
+ def generate_roadmap(goal, difficulty, pc, pine_index, client):
353
+ # This function would use the RAG system to generate a roadmap
354
+ # For now, return a placeholder
355
+ steps = [
356
+ "Learn Python Basics",
357
+ "Understand Data Structures & Algorithms",
358
+ "Master SQL",
359
+ "Explore Machine Learning Fundamentals",
360
+ "Build a Portfolio Project",
361
+ "Apply for Jobs"
362
+ ]
363
+ return render_text_roadmap(goal, steps)
364
+
365
+ def generate_visual_roadmap(goal, steps):
366
+ # This function would generate a visual roadmap using matplotlib or similar
367
+ # For now, return a placeholder plot
368
+ import matplotlib.pyplot as plt
369
+ fig, ax = plt.subplots()
370
+ ax.barh(steps, [1]*len(steps))
371
+ ax.set_title(f"Visual Roadmap for {goal}")
372
+ return fig
373
+
374
+
375
+ app.launch(debug=True)
376
+
377
+
378
+ """