Musabbirkm commited on
Commit
0af67a4
·
verified ·
1 Parent(s): f13f9fe

Upload 6 files

Browse files

imitial commit of careerboost

Files changed (7) hide show
  1. .gitattributes +1 -0
  2. Agent.py +292 -0
  3. LICENSE.md +108 -0
  4. README.md +116 -9
  5. app.py +879 -0
  6. logo.ico +3 -0
  7. requirements.txt +8 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ logo.ico filter=lfs diff=lfs merge=lfs -text
Agent.py ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import random
4
+ import asyncio
5
+ import aiohttp
6
+ from langchain_google_genai import ChatGoogleGenerativeAI
7
+ from langchain.agents import AgentType, initialize_agent, Tool
8
+ from langchain.prompts import PromptTemplate
9
+ from langchain.memory import ConversationBufferMemory
10
+ from langchain.tools import Tool
11
+ from duckduckgo_search import DDGS
12
+ from tenacity import retry, stop_after_attempt, wait_exponential
13
+ from functools import lru_cache
14
+ import re
15
+ import http.client
16
+ import urllib.parse
17
+
18
+ # Random User-Agent
19
+ def get_random_user_agent():
20
+ """ Various user-agent strings for Windows, macOS, Linux, Mobile devices, Tablets, Consoles, Smart TVs
21
+ This helps avoid being blocked by websites due to repetitive scraping
22
+ List of user agents truncated for brevity"""
23
+ USER_AGENTS = [
24
+ # Windows User Agents
25
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
26
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0',
27
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/91.0.864.59 Safari/537.36',
28
+ 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko',
29
+
30
+ # macOS User Agents
31
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
32
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15',
33
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:89.0) Gecko/20100101 Firefox/89.0',
34
+
35
+ # Linux User Agents
36
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
37
+ 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0',
38
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/91.0.4472.124 Safari/537.36',
39
+
40
+ # Mobile User Agents (Android)
41
+ 'Mozilla/5.0 (Linux; Android 10; SM-G975F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
42
+ 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
43
+ 'Mozilla/5.0 (Linux; Android 9; SM-G960F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
44
+
45
+ # Mobile User Agents (iOS)
46
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1',
47
+ 'Mozilla/5.0 (iPad; CPU OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1',
48
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/91.0.4472.124 Mobile/15E148 Safari/604.1', # Chrome on iOS
49
+
50
+ # Tablet User Agents
51
+ 'Mozilla/5.0 (Linux; Android 10; SM-T860) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Safari/537.36',
52
+ 'Mozilla/5.0 (Linux; Android 11; Lenovo TB-X606F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Safari/537.36',
53
+ 'Mozilla/5.0 (iPad; CPU OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1',
54
+
55
+ # Gaming Consoles
56
+ 'Mozilla/5.0 (PlayStation 4 8.52) AppleWebKit/605.1.15 (KHTML, like Gecko)',
57
+ 'Mozilla/5.0 (Nintendo Switch; WifiWebAuthApplet) AppleWebKit/609.4 (KHTML, like Gecko) NF/6.0.2.19.3 NintendoBrowser/5.1.0.22401',
58
+
59
+ # Smart TVs
60
+ 'Mozilla/5.0 (Web0S; Linux/SmartTV) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 WebAppManager',
61
+ 'Mozilla/5.0 (SMART-TV; Linux; Tizen 5.5) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.0 Chrome/91.0.4472.124 Safari/537.36',
62
+
63
+ ]
64
+ return random.choice(USER_AGENTS)
65
+
66
+ # Load API keys
67
+ google_api_key = os.getenv("GOOGLE_API_KEY")
68
+ rapidapi_key = os.getenv("RAPIDAPI_KEY")
69
+
70
+ if not google_api_key:
71
+ raise ValueError("Google API key not found.")
72
+ if not rapidapi_key:
73
+ raise ValueError("RapidAPI key not found.")
74
+
75
+ # Initialize LLM
76
+ llm = ChatGoogleGenerativeAI(
77
+ model="gemini-1.5-flash",
78
+ google_api_key=google_api_key
79
+ )
80
+
81
+ # DuckDuckGo search
82
+ def duckduckgo_search(query: str) -> str:
83
+ try:
84
+ with DDGS() as ddgs:
85
+ results = [r for r in ddgs.text(query, max_results=20)]
86
+ return json.dumps(results, indent=2)
87
+ except Exception as e:
88
+ return json.dumps({"error": f"Error in WebSearch: {str(e)}"}, indent=2)
89
+
90
+ duckduckgo_tool = Tool(
91
+ name="WebSearch",
92
+ func=duckduckgo_search,
93
+ description="Use this tool to search the web for job listings or interview questionss"
94
+ )
95
+
96
+
97
+ # Job finding agent
98
+ job_prompt = PromptTemplate(
99
+ input_variables=["input", "chat_history", "tools", "tool_names", "agent_scratchpad"],
100
+ template="""
101
+ You are an advanced job search assistant focused on finding job vacancies worldwide, with a special emphasis on India.
102
+ Your tasks:
103
+ - Find relevant job listings based on the field and location, including job titles, companies, locations, and links.
104
+ - Use the JobScraper tool first to get detailed job listings from job boards like Naukri.com, Shine.com, LinkedIn, and Indeed and other indian job boards.
105
+ - If JobScraper fails or returns no valid jobs, use WebSearch to find job-related information and extract relevant details.
106
+ - Avoid duplicate listings by checking job titles, companies, and locations.
107
+ - Format the output as a numbered list with: Title, Company, Location, Link, Source.
108
+ - If no jobs are found, clearly state so and provide any relevant links from WebSearch.
109
+ - Include all valid job details from JobScraper observations in the final answer.
110
+
111
+ Available tools: {tools}
112
+ Tool names: {tool_names}
113
+
114
+ User input: {input}
115
+ Chat history: {chat_history}
116
+ Agent scratchpad: {agent_scratchpad}
117
+ """
118
+ )
119
+
120
+ job_memory = ConversationBufferMemory(memory_key="chat_history")
121
+ job_agent = initialize_agent(
122
+ tools=[duckduckgo_tool],
123
+ llm=llm,
124
+ agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
125
+ verbose=True,
126
+ memory=job_memory,
127
+ handle_parsing_errors=True,
128
+ custom_prompt=job_prompt
129
+ )
130
+
131
+
132
+ # RapidAPI job searcher
133
+ def rapid_job_seacrher(job: str, location: str, pages: int = 1, country: str = "in") -> str:
134
+ conn = http.client.HTTPSConnection("jsearch.p.rapidapi.com")
135
+ headers = {
136
+ 'x-rapidapi-key': rapidapi_key,
137
+ 'x-rapidapi-host': "jsearch.p.rapidapi.com"
138
+ }
139
+ query = urllib.parse.quote(f"{job} jobs in {location}")
140
+ conn.request("GET", f"/search?query={query}&page=1&num_pages={pages}&country={country}&date_posted=all", headers=headers)
141
+ res = conn.getresponse()
142
+ data = res.read()
143
+ results = []
144
+
145
+ try:
146
+ data_json = json.loads(data.decode("utf-8"))
147
+ except json.JSONDecodeError as e:
148
+ return json.dumps({"error": f"Error parsing JSON: {str(e)}"}, indent=2)
149
+
150
+ for job in data_json.get('data', []):
151
+ title = job.get('job_title', 'N/A')
152
+ company = job.get('employer_name', 'N/A')
153
+ city = job.get('job_city', '')
154
+ state = job.get('job_state', '')
155
+ location_parts = [part for part in [city, state] if part]
156
+ location = ", ".join(location_parts) if location_parts else "N/A"
157
+ job_url = job.get('job_apply_link', 'N/A')
158
+ results.append({
159
+ "title": title,
160
+ "company": company,
161
+ "location": location,
162
+ "link": job_url,
163
+ "source": "RapidAPI"
164
+ })
165
+
166
+ return json.dumps(results if results else {"error": "No jobs found."}, indent=2)
167
+
168
+ # #Remove common markdown characters from text using regex
169
+ # def remove_markdown(text: str) -> str:
170
+ # patterns = [
171
+ # (r'^#+ ?', ''),
172
+ # (r'\*\*(.*?)\*\*', r'\1'),
173
+ # (r'\*(.*?)\*', r'\1'),
174
+ # (r'^- ?', ''),
175
+ # (r'\[([^\]]+)\]\([^\)]+\)', r'\1'),
176
+ # (r'^\s*:\s*', ''),
177
+ # (r'`{1,3}[^`]+`{1,3}', lambda m: m.group(0).replace('`', ''))
178
+ # ]
179
+ # cleaned_text = text
180
+ # for pattern, replacement in patterns:
181
+ # cleaned_text = re.sub(pattern, replacement, cleaned_text, flags=re.MULTILINE)
182
+ # cleaned_text = re.sub(r'\n\s*\n', '\n', cleaned_text).strip()
183
+ # return cleaned_text
184
+
185
+ # Interview preparation
186
+ def interview_preparer(job_field: str) -> str:
187
+ try:
188
+ if not job_field or not isinstance(job_field, str):
189
+ return "Error: Invalid job field provided."
190
+
191
+ search_queries = [
192
+ f"{job_field} interview questions 2022-2025",
193
+ f"site:reddit.com {job_field} interview questions",
194
+ f"site:quora.com {job_field} interview questions"
195
+ ]
196
+ search_results = []
197
+ for query in search_queries:
198
+ try:
199
+ result = duckduckgo_search(query)
200
+ if not result.startswith("Error"):
201
+ search_results.append(json.loads(result))
202
+ except Exception as e:
203
+ search_results.append({"source": query, "error": str(e)})
204
+
205
+ combined_results = json.dumps(search_results, indent=2)
206
+ interview_prompt = PromptTemplate(
207
+ input_variables=["job_field", "search_results"],
208
+ template="""
209
+ You are an interview preparation expert. Generate exactly 10 interview questions with detailed, professional answers for {job_field}. Do NOT provide links or references to external resources; focus on self-contained questions and answers.
210
+ Requirements:
211
+ - Include 4 technical questions, 3 behavioral questions, and 3 situational questions.
212
+ - Incorporate trends and frequently asked questions from 2022-2025.
213
+ - Use the search results for context to inform answers, but do not include raw search data or URLs in the output: {search_results}.
214
+ - Format as plain text with question numbers, type (Technical/Behavioral/Situational), questions, and answers.
215
+ Example:
216
+ 1. Technical: [Question]
217
+ Answer: [Detailed answer]
218
+ """
219
+ )
220
+ response = llm.invoke(interview_prompt.format(job_field=job_field, search_results=combined_results))
221
+ return response.content
222
+ except Exception as e:
223
+ return f"Error generating interview questions: {str(e)}"
224
+
225
+ interview_tool = Tool(
226
+ name="InterviewPreparer",
227
+ func=interview_preparer,
228
+ description="Generate 10 interview questions and answers for a job field (4 technical, 3 behavioral, 3 situational)."
229
+ )
230
+
231
+ interview_prompt = PromptTemplate(
232
+ input_variables=["input", "chat_history", "tools", "tool_names", "agent_scratchpad"],
233
+ template="""
234
+ You are an interview preparation assistant. Your task is to:
235
+ - Extract the job field from the user input (e.g., 'Prepare interview for data science' → job_field='data science').
236
+ - Use the InterviewPreparer tool exactly once to generate 10 interview questions with answers (4 technical, 3 behavioral, 3 situational).
237
+ - Do NOT attempt to create questions manually or simulate the tool's output.
238
+ - If the job field is unclear, return an error message asking for clarification.
239
+ - In the Final Answer, return only the tool's output as plain text, with no additional commentary.
240
+
241
+ Follow this strict format:
242
+ Thought: [Your reasoning]
243
+ Action: InterviewPreparer
244
+ Action Input: job_field="[job_field]"
245
+ Observation: [Tool output]
246
+ Final Answer: [Tool output]
247
+
248
+ Available tools: {tools}
249
+ Tool names: {tool_names}
250
+
251
+ User input: {input}
252
+ Chat history: {chat_history}
253
+ Agent scratchpad: {agent_scratchpad}
254
+ """
255
+ )
256
+
257
+ interview_memory = ConversationBufferMemory(memory_key="chat_history")
258
+ interview_agent = initialize_agent(
259
+ tools=[interview_tool],
260
+ llm=llm,
261
+ agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
262
+ verbose=True,
263
+ memory=interview_memory,
264
+ handle_parsing_errors=True,
265
+ custom_prompt=interview_prompt
266
+ )
267
+
268
+ # CV creator
269
+ cv_llm = ChatGoogleGenerativeAI(
270
+ model="gemini-1.5-flash",
271
+ google_api_key=google_api_key,
272
+ temperature=0.1,
273
+ max_output_tokens=2048
274
+ )
275
+
276
+ cv_prompt = PromptTemplate(
277
+ input_variables=["job_field", "experience"],
278
+ template="""
279
+ You are a professional CV writer. Create a concise, ATS-friendly CV for a {job_field} position based on the following details:
280
+ - User Details: Name: John Doe, Email: john.doe@example.com, Phone: +91-9876543210
281
+ - Experience and skills: {experience}
282
+ Include sections for Summary, Skills, Experience, and Education. Format as plain text for clarity.
283
+ """
284
+ )
285
+
286
+ def generate_cv(job_field: str, experience: str) -> str:
287
+ try:
288
+ prompt = cv_prompt.format(job_field=job_field, experience=experience)
289
+ response = cv_llm.invoke(prompt)
290
+ return response.content
291
+ except Exception as e:
292
+ return f"Error generating CV: {str(e)}"
LICENSE.md ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CareerBoost Code License
2
+ **Attribution-NonCommercial-API Limited License v2.0**
3
+
4
+ Copyright (c) 2025 Musabbir KM (<musabbirmushu@gmail.com>)
5
+
6
+ ---
7
+
8
+ ## 1. Definitions
9
+ - **Software**: The CareerBoost application, including all source code, documentation, and associated files in the repository.
10
+ - **Agent Code**: Proprietary AI logic, including but not limited to AI agents (Job Finding, Interview Preparation, CV Creator), training pipelines, prompts, and algorithms.
11
+ - **Public Interface Code**: Non-proprietary frontend code (e.g., Streamlit UI in `app.py`) excluding Agent Code.
12
+ - **Derivative Work**: Any modification, adaptation, or extension of the Software, including forks or integrations into other projects.
13
+ - **Third-Party APIs**: External services integrated into the Software, including but not limited to Google Gemini LLM, RapidAPI JSearch, and DuckDuckGo Search.
14
+ - **You**: Any individual, entity, or organization accessing, using, or modifying the Software.
15
+
16
+ ## 2. Grant of License
17
+ Subject to the terms of this License, Musabbir KM grants You a **non-exclusive, non-transferable, revocable, limited license** to:
18
+ - ✅ Use the hosted Software on Hugging Face Spaces (`https://musabbirkm-deephirex.hf.space`) for personal, non-commercial purposes.
19
+ - ✅ Study the Public Interface Code for educational purposes.
20
+ - ✅ Fork the repository for non-commercial testing or personal projects, provided all requirements below are met.
21
+ - ✅ Modify the Public Interface Code for personal learning, subject to attribution.
22
+
23
+ ## 3. Attribution Requirements
24
+ If You use, modify, or distribute any part of the Software or create a Derivative Work, You **MUST**:
25
+ - 📜 **Credit the Author**: Prominently display the following notice in the user interface (e.g., GUI, webpage), documentation, and source code of Your application or Derivative Work:
26
+ ### CareerBoost: Originally developed by Musabbir KM (musabbirmushu@gmail.com)
27
+
28
+ - 📜 Include a link to the original repository (`https://huggingface.co/spaces/musabbirkm/DeepHireX`) where feasible (e.g., in documentation or UI).
29
+ - 📜 Retain this License file, including the copyright notice, in any copy or Derivative Work.
30
+ - 📜 Ensure the attribution is visible to end users (e.g., in an "About" section, footer, or credits page) and not obscured or minimized.
31
+
32
+ Failure to comply with these attribution requirements voids this License.
33
+
34
+ ## 4. Permitted Use
35
+ You are permitted to:
36
+ - ✅ Access the Software via Hugging Face Spaces for job searching, interview preparation, or CV creation.
37
+ - ✅ Run the Software locally for personal use, provided You supply Your own API keys for Third-Party APIs.
38
+ - ✅ Share non-commercial Derivative Works, provided they comply with all attribution requirements and restrictions.
39
+
40
+ ## 5. Restrictions
41
+ You **MAY NOT**:
42
+ - ❌ Use the Software or any Derivative Work for commercial purposes, including but not limited to SaaS offerings, paid services, or revenue-generating products, without express written permission.
43
+ - ❌ Redistribute, sublicense, or transfer the Agent Code or any proprietary algorithms without prior authorization.
44
+ - ❌ Remove, alter, or obscure any copyright notices, attribution requirements, or this License in the Software or Derivative Works.
45
+ - ❌ Claim ownership of the Software, Agent Code, or core AI methodologies.
46
+ - ❌ Use the Software in a manner that violates the terms of any Third-Party APIs.
47
+ - ❌ Deploy the Software on platforms other than Hugging Face Spaces for public use without permission.
48
+ - ❌ Reverse-engineer, decompile, or attempt to extract the Agent Code or proprietary logic.
49
+
50
+ ## 6. Third-Party APIs
51
+ ⚠️ You acknowledge and agree that:
52
+ - The Software integrates Third-Party APIs (e.g., Google Gemini, RapidAPI), each governed by their own terms of service.
53
+ - You are solely responsible for:
54
+ - Obtaining and maintaining valid API keys.
55
+ - Complying with all Third-Party API terms, including usage limits and data privacy obligations.
56
+ - Any costs, liabilities, or damages arising from Your use of Third-Party APIs.
57
+ - Musabbir KM is not liable for interruptions, errors, or changes in Third-Party API availability.
58
+
59
+ ## 7. Ownership
60
+ - The Software and Agent Code are the intellectual property of **Musabbir KM**.
61
+ - All rights not expressly granted in this License are reserved.
62
+ - Contributions to the Software (e.g., pull requests) may require assignment of rights to Musabbir KM, to be agreed upon separately.
63
+
64
+ ## 8. Warranty Disclaimer
65
+ THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. MUSABBIR KM SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR INABILITY TO USE THE SOFTWARE, INCLUDING DATA LOSS, BUSINESS INTERRUPTION, OR API-RELATED COSTS.
66
+
67
+ ## 9. Termination
68
+ - This License is effective until terminated.
69
+ - It will terminate automatically if You violate any terms, including failure to provide attribution or unauthorized commercial use.
70
+ - Upon termination, You must cease all use of the Software and destroy any copies or Derivative Works in Your possession.
71
+
72
+ ## 10. Permission for Extended Use
73
+ For commercial use, Agent Code access, or public deployment beyond Hugging Face Spaces, You must obtain written permission by contacting:
74
+ - 📧 **Email**: musabbirmushu@gmail.com
75
+ - ✉️ **Required Information**:
76
+ - Your full name or organization name.
77
+ - Detailed description of the intended use case (e.g., app integration, research, commercial product).
78
+ - Project duration, scope, and expected user base.
79
+ - Whether Agent Code access is requested.
80
+ - Musabbir KM reserves the right to grant or deny permission at his sole discretion, potentially requiring a separate licensing agreement or fees.
81
+
82
+ ## 11. Enforcement
83
+ - Violations of this License, including unauthorized commercial use or failure to attribute, will result in legal action under applicable intellectual property laws.
84
+ - You agree to indemnify Musabbir KM for any claims, damages, or costs arising from Your misuse of the Software.
85
+
86
+ ## 12. Governing Law
87
+ This License is governed by the laws of **India**, without regard to conflict of law principles. Any disputes shall be resolved in the courts of **Kerala, India**.
88
+
89
+ ## 13. Severability
90
+ If any provision of this License is found to be unenforceable, the remaining provisions will continue in full force and effect.
91
+
92
+ ## 14. Amendments
93
+ Musabbir KM reserves the right to amend this License at any time. Updated versions will be posted in the repository, and continued use of the Software constitutes acceptance of the new terms.
94
+
95
+ ---
96
+
97
+ **Important Notice**: This License does not override or modify the terms of any Third-Party APIs integrated into the Software. You must independently comply with those terms.
98
+
99
+ **Contact**:
100
+ - Author: Musabbir KM
101
+ - Email: musabbirmushu@gmail.com
102
+ - Repository: https://huggingface.co/spaces/musabbirkm/DeepHireX
103
+
104
+ **Last Updated**: April 14, 2025
105
+
106
+ ---
107
+
108
+ *CareerBoost: Empowering Your Career Journey with AI-Driven Tools*
README.md CHANGED
@@ -1,14 +1,121 @@
1
  ---
 
2
  title: CareerBoost
3
- emoji: 🐠
4
- colorFrom: gray
5
- colorTo: blue
6
  sdk: streamlit
7
- sdk_version: 1.44.1
8
- app_file: app.py
9
- pinned: false
10
- license: other
11
- short_description: Your Job Search & Prep Companion
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
1
  ---
2
+ license: other
3
  title: CareerBoost
 
 
 
4
  sdk: streamlit
5
+ emoji: 📈
6
+ colorFrom: blue
7
+ colorTo: purple
8
+ pinned: true
9
+ short_description: AI-powered, futuristic, and career-accelerating
10
+ ---
11
+ # CareerBoost: Your Job Search & Prep Companion
12
+
13
+ **Empowering Your Career Journey with AI-Driven Tools**
14
+
15
+ **Creator**: Musabbir KM
16
+
17
+ ---
18
+
19
+ ## Overview
20
+
21
+ CareerBoost is an AI-powered web application designed to assist job seekers in finding job opportunities, preparing for interviews, and creating professional CVs. Built with a focus on usability and efficiency, it leverages advanced AI agents to deliver tailored results for users worldwide, with a special emphasis on the Indian job market.
22
+
23
+ ---
24
+
25
+ ## Features
26
+
27
+ CareerBoost offers four core functionalities, each powered by specialized AI agents:
28
+
29
+ 1. **Job Finding Agent**:
30
+ - Scrapes job listings from major job boards like Naukri.com, Shine.com, LinkedIn, and Indeed
31
+ - Supports location-based searches (e.g., "data science in Kochi")
32
+ - Displays detailed job information: title, company, location, salary range, and application link
33
+ - Intelligent fallback to web search when direct scraping fails
34
+ - Real-time alerts for new postings matching your profile
35
+ - Fetches structured job listings using the RapidAPI JSearch endpoint
36
+
37
+ 2. **Interview Preparation**:
38
+ - Generates 10 tailored interview questions and answers (4 technical, 3 behavioral, 3 situational)
39
+ - Incorporates latest trends (2022–2025) covering emerging skills like:
40
+ - Machine Learning Ops (MLOps)
41
+ - Ethical AI frameworks
42
+ - Cloud-native technologies
43
+ - Data visualization tools (Tableau, PowerBI)
44
+ - Includes company-specific question banks for top employers
45
+ - Provides sample answers with STAR (Situation-Task-Action-Result) format
46
+ - Delivers plain-text output for easy review and practice
47
+
48
+ 3. **CV Creator**:
49
+ - Builds ATS-friendly CVs optimized for applicant tracking systems
50
+ - Custom templates for different experience levels (Entry, Mid, Senior)
51
+ - Includes smart sections:
52
+ - Professional Summary with keywords
53
+ - Skills Matrix with proficiency levels
54
+ - Experience with measurable achievements
55
+ - Education with relevant coursework
56
+ - Auto-formatting for consistent styling
57
+ - Export options (PDF, DOCX, plain text)
58
+
59
+ 4. **Career Insights**:
60
+ - Daily curated feed of job market trends and tech news
61
+ - Company watchlists with hiring alerts
62
+ - Salary benchmarking by role and location
63
+ - Emerging technology spotlights (AI, Blockchain, IoT)
64
+ - Industry-specific reports (IT, Healthcare, Finance)
65
+ - Local job market heatmaps
66
+ - Skill gap analysis with learning recommendations
67
+ - Networking event calendars
68
+
69
+ ---
70
+
71
+ ## Technologies Used
72
+
73
+ CareerBoost is built with a robust tech stack to ensure performance and scalability:
74
+
75
+ - **Frontend**:
76
+ - [Streamlit](https://streamlit.io/) (v1.29.0): For the interactive web interface.
77
+ - Custom CSS: For enhanced UI styling (tabs, cards, logo display).
78
+
79
+ - **Backend & AI**:
80
+ - [LangChain](https://python.langchain.com/) (v0.2.16): For agent orchestration and tool integration.
81
+ - [Google Gemini LLM](https://cloud.google.com/vertex-ai/docs/generative-ai/model-reference/gemini) (via langchain-google-genai v1.0.8): Powers natural language processing and generation.
82
+ - [DuckDuckGo Search](https://github.com/deedy5/duckduckgo_search) (v6.2.11): For fallback web searches.
83
+ - [RapidAPI JSearch](https://rapidapi.com/letscrape-6bRBaM6guO5/api/jsearch): For structured job data.
84
+ - [aiohttp](https://docs.aiohttp.org/) (v3.10.5): For asynchronous web scraping.
85
+ - [Selectolax](https://github.com/rushter/selectolax) (v0.3.21): For efficient HTML parsing.
86
+ - [Tenacity](https://github.com/jd/tenacity) (v8.5.0): For retry logic in scraping.
87
+ - [python-dotenv](https://github.com/theskumar/python-dotenv) (v1.0.1): For environment variable management.
88
+
89
+ ---
90
+
91
+ ## Agent Info
92
+
93
+ CareerBoost leverages four specialized AI agents, each designed for a specific task:
94
+
95
+ - **Job Finding Agent**:
96
+ - Uses a ReAct (Reasoning + Acting) framework to scrape job boards asynchronously.
97
+ - Handles errors like rate limits and timeouts with retries and randomized delays.
98
+ - Formats output as a numbered list for clarity.
99
+
100
+ - **RapidAPI Job Search Agent**:
101
+ - Queries the JSearch API for structured job data.
102
+ - Processes results into a consistent format (title, company, location, link, source).
103
+
104
+ - **Interview Preparation Agent**:
105
+ - Generates 10 questions and answers using the Google Gemini LLM.
106
+ - Integrates web search insights to reflect recent trends (e.g., cloud computing, ethical AI).
107
+ - Fixed to prevent iteration limit errors by enforcing strict tool usage.
108
+
109
+ - **CV Creator Agent**:
110
+ - Generates ATS-friendly CVs with a single LLM call.
111
+ - Customizes content based on user input, ensuring relevance to the job field.
112
+
113
  ---
114
 
115
+ ## Get In Touch
116
+ - We’d love to hear from you! Whether you have questions, feedback, or just want to chat, reach out to us anytime.
117
+ - 📧 **Email**: [musabbirmushu@gmail.com](mailto:musabbirmushu@gmail.com)
118
+ - 💼 **LinkedIn**: [CareerBoost LinkedIn](https://www.linkedin.com/in/muhammed-musabbir-km-0302b8212utm_source=share&utm_campaign=share_via&utm_content=profile&utm_medium=android_appt)
119
+ - 🌐 **Website**: [www.careerboost.ai](https://omnicipher.onrender.com)
120
+ - ⌨️ **GitHub**: [CareerBoost GitHub](https://github.com/musabbirkm)
121
+
app.py ADDED
@@ -0,0 +1,879 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import requests
3
+ from urllib.parse import quote_plus
4
+ from duckduckgo_search import DDGS
5
+ import urllib.parse
6
+ import json
7
+ import http.client
8
+ from langchain.prompts import PromptTemplate
9
+ from langchain_google_genai import ChatGoogleGenerativeAI
10
+ from reportlab.lib.pagesizes import letter
11
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, ListFlowable, ListItem
12
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
13
+ from io import BytesIO
14
+ from newsapi import NewsApiClient
15
+ from datetime import datetime, timedelta
16
+ import urllib.request
17
+ import os
18
+ import base64
19
+
20
+
21
+ # Streamlit page configuration
22
+ st.set_page_config(
23
+ page_title="CareerBoost",
24
+ page_icon="💼",
25
+ layout="wide",
26
+ initial_sidebar_state="expanded"
27
+ )
28
+ # Load API keys
29
+ try:
30
+ serp_api_key = os.getenv("serp_api_key")
31
+ rapidapi_key = os.getenv("rapidapi_key")
32
+ google_api_key = os.getenv("google_api_key")
33
+ gnews_api_key = os.getenv("gnews_api_key")
34
+ newsapi_key = os.getenv("newsapi_ke")
35
+ except KeyError as e:
36
+ st.error(f"Missing API key: {e}. Please configure it in secrets.toml.")
37
+ st.stop()
38
+
39
+ # Custom CSS
40
+ st.markdown("""
41
+ <style>
42
+ .main {
43
+ background-color: #f0f2f6;
44
+ padding: 20px;
45
+ border-radius: 10px;
46
+ }
47
+ .stButton>button {
48
+ background-color: #4CAF50;
49
+ color: white;
50
+ border-radius: 5px;
51
+ padding: 10px 20px;
52
+ font-weight: bold;
53
+ }
54
+ .stButton>button:hover {
55
+ background-color: #45a049;
56
+ }
57
+ .stTextInput>div>input, .stTextArea textarea {
58
+ border-radius: 5px;
59
+ padding: 10px;
60
+ }
61
+ .stSelectbox>div>div {
62
+ border-radius: 5px;
63
+ }
64
+ .header {
65
+ text-align: center;
66
+ margin-bottom: 20px;
67
+ }
68
+ .caption {
69
+ text-align: center;
70
+ color: #666;
71
+ font-style: italic;
72
+ }
73
+ .logo {
74
+ display: block;
75
+ margin: 0 auto;
76
+ width: 150px;
77
+ }
78
+ .card {
79
+ background-color: white;
80
+ padding: 15px;
81
+ border-radius: 10px;
82
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
83
+ margin-bottom: 20px;
84
+ }
85
+ </style>
86
+ """, unsafe_allow_html=True)
87
+
88
+ # Sidebar navigation
89
+ st.sidebar.title("CareerBoost")
90
+ st.sidebar.markdown("""
91
+ **Your AI-powered career assistant**
92
+ *Smart tools for job search, CV optimization, and interview success.*
93
+ """)
94
+ page = st.sidebar.selectbox(
95
+ "Choose a section",
96
+ ["Home", "Job Finding", "CV Maker", "Interview Preparation", "Career Insights", "About"]
97
+ )
98
+ st.sidebar.markdown("""
99
+ ### ✨ Key Features:
100
+ - **AI-Powered Job Matching**
101
+ - **ATS-Friendly CV Builder**
102
+ - **Personalized Interview Prep**
103
+ - **Real-Time Career Insights**
104
+ """)
105
+ st.sidebar.markdown("""
106
+ ---
107
+ **Ready to boost your career?**
108
+ Start with our [CV Maker](#) or [Job Finder](#)!
109
+ """)
110
+
111
+ st.sidebar.caption("v2.1.0 | Last updated: April 2024")
112
+
113
+
114
+ # Home page
115
+ if page == "Home":
116
+ st.markdown("""
117
+ <style>
118
+ .header {
119
+ background: linear-gradient(135deg, #2c3e50, #4a6491);
120
+ padding: 20px;
121
+ border-radius: 10px;
122
+ color: white;
123
+ box-shadow: 0 4px 8px rgba(0,0,0,0.2);
124
+ margin-bottom: 20px;
125
+ }
126
+ .feature-card {
127
+ background-color: #2d3748;
128
+ border-radius: 10px;
129
+ padding: 20px;
130
+ margin: 10px 0;
131
+ box-shadow: 0 2px 4px rgba(0,0,0,0.2);
132
+ border-left: 4px solid #4a6491;
133
+ transition: transform 0.3s;
134
+ color: #f7fafc;
135
+ }
136
+ .feature-card:hover {
137
+ transform: translateY(-5px);
138
+ box-shadow: 0 6px 12px rgba(0,0,0,0.3);
139
+ background-color: #3c4a5e;
140
+ }
141
+ .stats-container {
142
+ display: flex;
143
+ justify-content: space-around;
144
+ text-align: center;
145
+ margin: 30px 0;
146
+ }
147
+ .stat-item {
148
+ background: #2d3748;
149
+ padding: 15px;
150
+ border-radius: 8px;
151
+ width: 23%;
152
+ color: #f7fafc;
153
+ box-shadow: 0 2px 4px rgba(0,0,0,0.2);
154
+ }
155
+ .testimonial {
156
+ font-style: italic;
157
+ background: #2d3748;
158
+ padding: 20px;
159
+ border-radius: 10px;
160
+ border-left: 4px solid #4a6491;
161
+ margin: 15px 0;
162
+ color: #f7fafc;
163
+ box-shadow: 0 2px 4px rgba(0,0,0,0.2);
164
+ }
165
+ body {
166
+ color: #f7fafc;
167
+ background-color: #1a202c;
168
+ }
169
+ .stApp {
170
+ background-color: #1a202c;
171
+ }
172
+ .caption {
173
+ color: #a0aec0;
174
+ font-size: 1.1em;
175
+ margin-bottom: 20px;
176
+ }
177
+ h1, h2, h3, h4, h5, h6 {
178
+ color: #f7fafc !important;
179
+ }
180
+ p {
181
+ color: #e2e8f0 !important;
182
+ }
183
+ </style>
184
+ """, unsafe_allow_html=True)
185
+
186
+ st.markdown('<div class="header"><h1>🚀 CareerBoost</h1></div>', unsafe_allow_html=True)
187
+ st.markdown('<div class="caption">Your one-stop platform for job hunting, CV creation, and career insights</div>',
188
+ unsafe_allow_html=True)
189
+
190
+ logo_path = "logo.ico"
191
+ if os.path.exists(logo_path):
192
+ col1, col2, col3 = st.columns([1,2,1])
193
+ with col2:
194
+ with open(logo_path, "rb") as f:
195
+ logo_bytes = f.read()
196
+ st.markdown(
197
+ f'<div style="text-align: center;"><img src="data:image/x-icon;base64,{base64.b64encode(logo_bytes).decode()}" width="150"></div>',
198
+ unsafe_allow_html=True
199
+ )
200
+ else:
201
+ st.warning("Logo file (logo.png) not found. Please upload it to the project directory.")
202
+
203
+ st.markdown("""
204
+ ## Welcome to Your Career Transformation
205
+
206
+ CareerBoost is your **AI-powered career companion** designed to help you navigate every step of your professional
207
+ journey with confidence. Whether you're looking for your dream job, optimizing your resume, or preparing for
208
+ interviews, we've got you covered with smart, personalized tools.
209
+ """)
210
+
211
+ st.markdown("""
212
+ <div class="stats-container">
213
+ <div class="stat-item">
214
+ <h3>250K+</h3>
215
+ <p>Professionals Helped</p>
216
+ </div>
217
+ <div class="stat-item">
218
+ <h3>3x</h3>
219
+ <p>Faster Job Placement</p>
220
+ </div>
221
+ <div class="stat-item">
222
+ <h3>40%</h3>
223
+ <p>More Interviews</p>
224
+ </div>
225
+ <div class="stat-item">
226
+ <h3>95%</h3>
227
+ <p>User Satisfaction</p>
228
+ </div>
229
+ </div>
230
+ """, unsafe_allow_html=True)
231
+
232
+ st.markdown("## ✨ How CareerBoost Helps You Succeed")
233
+
234
+ features = [
235
+ {
236
+ "title": "Smart Job Matching",
237
+ "desc": "Our AI scans thousands of listings to find the perfect matches for your skills and aspirations.",
238
+ "icon": "🔍"
239
+ },
240
+ {
241
+ "title": "ATS-Optimized CV Builder",
242
+ "desc": "Create resumes that beat applicant tracking systems with our intelligent templates.",
243
+ "icon": "📄"
244
+ },
245
+ {
246
+ "title": "AI Interview Coach",
247
+ "desc": "Practice with realistic mock interviews and get instant feedback on your responses.",
248
+ "icon": "💬"
249
+ },
250
+ {
251
+ "title": "Career Navigator",
252
+ "desc": "Get personalized career path recommendations based on your profile and goals.",
253
+ "icon": "🧭"
254
+ }
255
+ ]
256
+
257
+ for feature in features:
258
+ st.markdown(f"""
259
+ <div class="feature-card">
260
+ <h3>{feature['icon']} {feature['title']}</h3>
261
+ <p>{feature['desc']}</p>
262
+ </div>
263
+ """, unsafe_allow_html=True)
264
+
265
+ st.markdown("""
266
+ ## Ready to Boost Your Career?
267
+ Get started today by selecting one of the options from the sidebar:
268
+ """)
269
+
270
+ # Job Finding Section
271
+ elif page == "Job Finding":
272
+ st.title("🔍 Job Finding")
273
+ st.markdown("Search for job opportunities tailored to your preferences.")
274
+
275
+ def build_google_search_link(title, company):
276
+ query = f"{title} {company} apply job"
277
+ return f"https://www.google.com/search?q={quote_plus(query)}"
278
+
279
+ def search_serp(query, location, experience='fresher', job_category='full-time', num_results=10):
280
+ params = {
281
+ "engine": "google_jobs",
282
+ "q": f"{query} {job_category}",
283
+ "location": location,
284
+ "experience": experience,
285
+ "api_key": serp_api_key
286
+ }
287
+ try:
288
+ response = requests.get("https://serpapi.com/search", params=params)
289
+ response.raise_for_status()
290
+ data = response.json()
291
+ jobs = data.get("jobs_results", [])[:num_results]
292
+ results = []
293
+ for job in jobs:
294
+ result = {
295
+ "title": job.get('title', 'N/A'),
296
+ "company": job.get('company_name', 'N/A'),
297
+ "location": job.get('location', 'N/A'),
298
+ "posted": job.get('detected_extensions', {}).get('posted_at', 'N/A'),
299
+ "description": job.get('description', '')[:200] + "...",
300
+ "apply_link": job.get("job_google_link") or build_google_search_link(job.get('title', ''), job.get('company_name', 'Unknown')),
301
+ "source": "SerpAPI",
302
+ "category": job_category
303
+ }
304
+ results.append(result)
305
+ return results
306
+ except requests.exceptions.RequestException:
307
+ return [{"error": "Server error, please try again later."}]
308
+
309
+ def duckduckgo_job_search(query: str, job_category: str) -> list:
310
+ try:
311
+ with DDGS() as ddgs:
312
+ results = [r for r in ddgs.text(f"{query} {job_category}", max_results=20)]
313
+ formatted_results = []
314
+ for result in results:
315
+ formatted_results.append({
316
+ "title": result.get('title', 'N/A'),
317
+ "company": 'N/A', # DuckDuckGo doesn't provide company name reliably
318
+ "location": 'N/A', # DuckDuckGo doesn't provide location reliably
319
+ "apply_link": result.get('href', '#'),
320
+ "description": result.get('body', 'No description available')[:200] + "...",
321
+ "posted": None,
322
+ "source": "DuckDuckGo",
323
+ "category": job_category
324
+ })
325
+ return formatted_results
326
+ except Exception as e:
327
+ return [{"error": f"Error in WebSearch: {str(e)}"}]
328
+
329
+ def job_search(field, location, experience, job_category='full-time'):
330
+ query = f"find {field} job in {location} for {experience}"
331
+ return duckduckgo_job_search(query, job_category)
332
+
333
+ def rapid_job_searcher(job: str, location: str, pages: int = 1, country: str = "us") -> list:
334
+ conn = http.client.HTTPSConnection("jsearch.p.rapidapi.com")
335
+ headers = {
336
+ 'x-rapidapi-key': rapidapi_key,
337
+ 'x-rapidapi-host': "jsearch.p.rapidapi.com"
338
+ }
339
+ query = urllib.parse.quote(f"{job} jobs in {location}")
340
+ conn.request("GET", f"/search?query={query}&page=1&num_pages={pages}&country={country}&date_posted=all",
341
+ headers=headers)
342
+ res = conn.getresponse()
343
+ data = res.read()
344
+ results = []
345
+ try:
346
+ data_json = json.loads(data.decode("utf-8"))
347
+ except json.JSONDecodeError as e:
348
+ return [{"error": f"Error parsing JSON: {str(e)}"}]
349
+ for job in data_json.get('data', []):
350
+ city = job.get('job_city', '')
351
+ state = job.get('job_state', '')
352
+ location_parts = [part for part in [city, state] if part]
353
+ results.append({
354
+ "title": job.get('job_title', 'N/A'),
355
+ "company": job.get('employer_name', 'N/A'),
356
+ "location": ", ".join(location_parts) if location_parts else "N/A",
357
+ "posted": job.get('job_posted_at_datetime_utc', 'N/A'),
358
+ "description": job.get('job_description', 'N/A')[:200] + "...",
359
+ "apply_link": job.get('job_apply_link', '#'),
360
+ "source": "RapidAPI",
361
+ "category": None
362
+ })
363
+ return results if results else [{"error": "No jobs found."}]
364
+
365
+ job_categories = ['full-time', 'part-time', 'intern', 'contract', 'temporary']
366
+ experience_levels = ['fresher', 'experienced', 'senior']
367
+
368
+ with st.form("job_search_form"):
369
+ col1, col2 = st.columns(2)
370
+ with col1:
371
+ job = st.text_input("Job Title (e.g., Software Engineer)", "Software Engineer")
372
+ location = st.text_input("Location (e.g., Kochi)", "Kochi")
373
+ with col2:
374
+ experience = st.selectbox("Experience Level", experience_levels)
375
+ category = st.selectbox("Job Category", job_categories)
376
+ submit = st.form_submit_button("Search Jobs")
377
+
378
+ if submit:
379
+ with st.spinner("Searching for jobs..."):
380
+ rapid_results = rapid_job_searcher(job, location)
381
+ ddg_results = job_search(job, location, experience, category)
382
+ serp_results = search_serp(job, location, experience, category)
383
+ all_results = {'RapidAPI': rapid_results, 'DuckDuckGo': ddg_results, 'SerpAPI': serp_results}
384
+
385
+ for source, results in all_results.items():
386
+ st.subheader(f"Jobs from {source}")
387
+ if results and not any("error" in r for r in results):
388
+ for result in results:
389
+ with st.container():
390
+ st.markdown(f"""
391
+ <div class="card">
392
+ <h4>{result.get('title', 'N/A')}</h4>
393
+ <p><strong>Company:</strong> {result.get('company', 'N/A')}</p>
394
+ <p><strong>Location:</strong> {result.get('location', 'N/A')}</p>
395
+ <p><strong>Posted:</strong> {result.get('posted', 'N/A')}</p>
396
+ <p><strong>Description:</strong> {result.get('description', 'No description available')}</p>
397
+ <a href="{result.get('apply_link', '#')}" target="_blank">Apply Now</a>
398
+ </div>
399
+ """, unsafe_allow_html=True)
400
+ else:
401
+ st.error(results[0].get("error", "No results found."))
402
+
403
+ # CV Maker Section
404
+ elif page == "CV Maker":
405
+ st.title("📝 CV Maker")
406
+ st.markdown("Create a professional, ATS-friendly CV tailored to your job role.")
407
+
408
+ cv_llm = ChatGoogleGenerativeAI(
409
+ model="gemini-1.5-flash",
410
+ google_api_key=google_api_key,
411
+ temperature=0.1,
412
+ max_output_tokens=2048
413
+ )
414
+
415
+ cv_prompt = PromptTemplate(
416
+ input_variables=["job_field", "experience_level", "years_experience", "key_skills", "education"],
417
+ template="""
418
+ You are an expert CV writer with deep knowledge of ATS-friendly formatting and industry-specific requirements.
419
+ Create a professional, concise, and tailored CV for a {job_field} position based on the following user details:
420
+
421
+ - Experience: {experience_level} ({years_experience} years)
422
+ - Skills: {key_skills}
423
+ - Education: {education}
424
+
425
+ Structure:
426
+ === Contact ===
427
+ - Name: John Doe
428
+ - Email: john.doe@example.com
429
+ - Phone: +91-9876543210
430
+ - LinkedIn: https://github.com/musabbirkm
431
+ - Portfolio/GitHub: https://huggingface.co/spaces/Musabbirkm
432
+
433
+ == Professional Summary ==
434
+ - 3-4 sentences highlighting expertise in {job_field}, key achievements, and career goals.
435
+ - Use action verbs (e.g., "Led," "Optimized," "Developed") and quantifiable results.
436
+
437
+ == Projects ==
438
+ - Project Name | [GitHub/Live Link]
439
+ • Technologies used: {key_skills}
440
+ • Key outcome: [Measurable result]
441
+
442
+ === Skills ===
443
+ - 6-10 relevant skills including {key_skills}
444
+
445
+ === Experience ===
446
+ [2-3 roles based on {experience_level}]
447
+ - Title @ Company (Years)
448
+ • Metric-driven achievements
449
+ • Action-oriented responsibilities
450
+
451
+ === Education ===
452
+ {Education}
453
+ - Degree Name, University Name | Year
454
+ • Relevant coursework: [Course 1], [Course 2]
455
+ • Thesis/Project: [If applicable]
456
+
457
+ === Certifications ===
458
+ - [Relevant certifications]
459
+
460
+ Guidelines:
461
+ 1. Use action verbs and metrics
462
+ 2. Match seniority to {experience_level}
463
+ 3. ATS-optimized plain text format
464
+ 4. Field-specific keywords
465
+ """
466
+ )
467
+
468
+
469
+ def generate_cv(job_field: str, experience_level: str, years_experience: str, key_skills: str,
470
+ education: str) -> str:
471
+ try:
472
+ prompt = cv_prompt.format(
473
+ job_field=job_field,
474
+ experience_level=experience_level,
475
+ years_experience=years_experience,
476
+ key_skills=key_skills,
477
+ education=education,
478
+ )
479
+ response = cv_llm.invoke(prompt)
480
+ return response.content
481
+ except Exception as e:
482
+ return f"Error generating CV: {str(e)}"
483
+
484
+
485
+ def generate_cv_pdf(cv_content: str) -> BytesIO:
486
+ buffer = BytesIO()
487
+ doc = SimpleDocTemplate(buffer, pagesize=letter)
488
+ styles = getSampleStyleSheet()
489
+ heading_style = ParagraphStyle(name='Heading', fontSize=14, leading=16, spaceAfter=12,
490
+ fontName='Helvetica-Bold')
491
+ body_style = ParagraphStyle(name='Body', fontSize=11, leading=14, spaceAfter=8, fontName='Helvetica')
492
+ bullet_style = ParagraphStyle(name='Bullet', fontSize=11, leading=14, leftIndent=20, bulletIndent=10,
493
+ spaceAfter=8, fontName='Helvetica')
494
+
495
+ flowables = []
496
+ sections = cv_content.split('===')
497
+ for i in range(0, len(sections), 2):
498
+ if i + 1 >= len(sections):
499
+ break
500
+ title = sections[i].strip()
501
+ content = sections[i + 1].strip().split('\n')
502
+ flowables.append(Paragraph(title, heading_style))
503
+ flowables.append(Spacer(1, 6))
504
+ if title == "Skills" or title == "Certifications":
505
+ bullet_items = [ListItem(Paragraph(line.strip(), bullet_style)) for line in content if line.strip()]
506
+ flowables.append(ListFlowable(bullet_items, bulletType='bullet', start='circle'))
507
+ else:
508
+ for line in content:
509
+ if line.strip():
510
+ flowables.append(Paragraph(line.strip(), body_style))
511
+ flowables.append(Spacer(1, 12))
512
+ doc.build(flowables)
513
+ buffer.seek(0)
514
+ return buffer
515
+
516
+
517
+ with st.form("cv_form"):
518
+ col1, col2 = st.columns(2)
519
+ with col1:
520
+ job_field = st.text_input("Job Field (e.g., Software Engineer)", "Software Engineer")
521
+ experience_level = st.selectbox("Experience Level", ["Fresher", "Experienced", "Senior"])
522
+ years_experience = st.text_input("Years of Experience (e.g., 2)", "2")
523
+ with col2:
524
+ key_skills = st.text_area("Key Skills (comma-separated, e.g., Python, SQL)", "Python, SQL, JavaScript")
525
+ education = st.text_area("Education (e.g., B.Tech in CS, XYZ University, 2020)",
526
+ "B.Tech in CS, XYZ University, 2020")
527
+ submit = st.form_submit_button("Generate CV")
528
+
529
+ if submit:
530
+ with st.spinner("Generating CV..."):
531
+ cv_content = generate_cv(job_field, experience_level, years_experience, key_skills, education)
532
+ st.session_state['last_cv'] = cv_content
533
+ if not cv_content.startswith("Error"):
534
+ st.success("CV generated successfully!")
535
+ st.markdown("### Generated CV")
536
+ st.text_area("CV Content", cv_content, height=400)
537
+ st.download_button(
538
+ label="Download CV (Text)",
539
+ data=cv_content,
540
+ file_name="John_Doe_CV.txt",
541
+ mime="text/plain"
542
+ )
543
+ pdf_buffer = generate_cv_pdf(cv_content)
544
+ st.download_button(
545
+ label="Download CV (PDF)",
546
+ data=pdf_buffer,
547
+ file_name="John_Doe_CV.pdf",
548
+ mime="application/pdf"
549
+ )
550
+ else:
551
+ st.error(cv_content)
552
+
553
+ # Interview Preparation Section
554
+ elif page == "Interview Preparation":
555
+ st.title("🎤 Interview Preparation")
556
+ st.markdown("Prepare for your next interview with tailored questions and answers.")
557
+
558
+ llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash", google_api_key=google_api_key)
559
+
560
+
561
+ def duckduckgo_search(query: str) -> str:
562
+ try:
563
+ with DDGS() as ddgs:
564
+ results = [r for r in ddgs.text(query, max_results=5)]
565
+ return json.dumps(results, indent=2)
566
+ except Exception as e:
567
+ return f"Error in DuckDuckGo search: {str(e)}"
568
+
569
+
570
+ def interview_preparer(job_field: str) -> str:
571
+ try:
572
+ if not job_field or not isinstance(job_field, str):
573
+ return "Error: Invalid job field provided."
574
+ search_queries = [
575
+ f"{job_field} interview questions 2022-2025",
576
+ f"site:reddit.com {job_field} interview questions",
577
+ f"site:quora.com {job_field} interview questions"
578
+ ]
579
+ search_results = []
580
+ for query in search_queries:
581
+ try:
582
+ result = duckduckgo_search(query)
583
+ if not result.startswith("Error"):
584
+ search_results.append(json.loads(result))
585
+ except Exception as e:
586
+ search_results.append({"source": query, "error": str(e)})
587
+ combined_results = json.dumps(search_results, indent=2)
588
+ interview_prompt = PromptTemplate(
589
+ input_variables=["job_field", "search_results"],
590
+ template="""
591
+ You are an interview preparation expert. Generate exactly 10 interview questions with detailed, professional answers for {job_field}. Do NOT provide links or references to external resources; focus on self-contained questions and answers.
592
+ Requirements:
593
+ - Include 4 technical questions, 3 behavioral questions, and 3 situational questions.
594
+ - Incorporate trends and frequently asked questions from 2022-2025.
595
+ - Use the search results for context to inform answers, but do not include raw search data or URLs in the output: {search_results}.
596
+ - Format as plain text with question numbers, type (Technical/Behavioral/Situational), questions, and answers.
597
+ Example:
598
+ 1. Technical: [Question]
599
+ Answer: [Detailed answer]
600
+ """
601
+ )
602
+ response = llm.invoke(interview_prompt.format(job_field=job_field, search_results=combined_results))
603
+ return response.content
604
+ except Exception as e:
605
+ return f"Error generating interview questions: {str(e)}"
606
+
607
+
608
+ with st.form("interview_form"):
609
+ job_field = st.text_input("Job Field (e.g., Software Engineer)", "Software Engineer")
610
+ submit = st.form_submit_button("Generate Questions")
611
+
612
+ if submit:
613
+ with st.spinner("Generating interview questions..."):
614
+ questions = interview_preparer(job_field)
615
+ st.session_state['last_questions'] = questions
616
+ if not questions.startswith("Error"):
617
+ st.success("Interview questions generated successfully!")
618
+ st.markdown("### Interview Questions")
619
+ st.text_area("Questions and Answers", questions, height=400)
620
+ st.download_button(
621
+ label="Download Questions",
622
+ data=questions,
623
+ file_name="Interview_Questions.txt",
624
+ mime="text/plain"
625
+ )
626
+ else:
627
+ st.error(questions)
628
+
629
+ # Career Insights Section
630
+ elif page == "Career Insights":
631
+ st.title("📰 Career Insights")
632
+ st.markdown("Stay updated with the latest job market trends and company hiring news.")
633
+
634
+ newsapi = NewsApiClient(api_key=newsapi_key)
635
+
636
+ def get_gnews_articles():
637
+ url = f"https://gnews.io/api/v4/search?q=job%20market%20OR%20employment%20OR%20hiring%20OR%20recruitment%20OR%20careers%20OR%20job%20opportunities%20India%20OR%20tech%20OR%20IT%20OR%20technology&lang=en&country=in&max=10&apikey={gnews_api_key}"
638
+ try:
639
+ with urllib.request.urlopen(url) as response:
640
+ data = json.loads(response.read().decode("utf-8"))
641
+ if "articles" in data:
642
+ return [
643
+ {
644
+ "title": article["title"],
645
+ "description": article.get("description", "No description available"),
646
+ "source": article["source"]["name"],
647
+ "published_at": article["publishedAt"],
648
+ "url": article["url"]
649
+ }
650
+ for article in data["articles"]
651
+ ]
652
+ return []
653
+ except urllib.error.URLError as e:
654
+ st.error(f"Failed to fetch GNews: {e.reason}")
655
+ return []
656
+
657
+ def get_indian_job_news():
658
+ try:
659
+ yesterday = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d') # Extended to 7 days
660
+ if not isinstance(yesterday, str):
661
+ raise ValueError("Invalid date format for from_param")
662
+ job_news = newsapi.get_everything(
663
+ q='(jobs OR hiring OR recruitment OR employment OR "job market") AND (India OR Indian)',
664
+ language='en',
665
+ sort_by='publishedAt',
666
+ from_param=yesterday,
667
+ page_size=10
668
+ )
669
+ return [
670
+ {
671
+ "title": article["title"],
672
+ "description": article.get("description", "No description available"),
673
+ "source": article["source"]["name"],
674
+ "published_at": article["publishedAt"],
675
+ "url": article["url"]
676
+ }
677
+ for article in job_news.get("articles", [])
678
+ ]
679
+ except newsapi.newsapi_exception.NewsApiException as e:
680
+ st.error(f"NewsAPI error fetching job news: {e.get_message()}")
681
+ return []
682
+ except Exception as e:
683
+ st.error(f"Unexpected error fetching job news: {str(e)}")
684
+ return []
685
+
686
+ def get_indian_tech_news():
687
+ try:
688
+ domains = 'economictimes.indiatimes.com,livemint.com,indiatoday.in'
689
+ tech_news = newsapi.get_everything(
690
+ q='(tech OR IT OR technology OR startup) AND (India OR Indian)',
691
+ domains=domains,
692
+ language='en',
693
+ sort_by='relevancy',
694
+ page_size=10
695
+ )
696
+ return [
697
+ {
698
+ "title": article["title"],
699
+ "description": article.get("description", "No description available"),
700
+ "source": article["source"]["name"],
701
+ "published_at": article.get("publishedAt", "N/A"),
702
+ "url": article["url"]
703
+ }
704
+ for article in tech_news.get("articles", [])
705
+ ]
706
+ except newsapi.newsapi_exception.NewsApiException as e:
707
+ st.error(f"NewsAPI error fetching tech news: {e.get_message()}")
708
+ return []
709
+ except Exception as e:
710
+ st.error(f"Unexpected error fetching tech news: {str(e)}")
711
+ return []
712
+
713
+ def get_company_hiring_news():
714
+ companies = ['TCS', 'Infosys', 'Wipro', 'HCL', 'Tech Mahindra']
715
+ company_news = []
716
+ try:
717
+ for company in companies:
718
+ news = newsapi.get_everything(
719
+ q=f'{company} AND (hiring OR recruitment OR jobs)',
720
+ language='en',
721
+ page_size=3
722
+ )
723
+ company_articles = [
724
+ {
725
+ "title": article["title"],
726
+ "description": article.get("description", "No description available"),
727
+ "source": article["source"]["name"],
728
+ "published_at": article.get("publishedAt", "N/A"),
729
+ "url": article["url"],
730
+ "company": company
731
+ }
732
+ for article in news.get("articles", [])
733
+ ]
734
+ company_news.extend(company_articles)
735
+ return company_news
736
+ except newsapi.newsapi_exception.NewsApiException as e:
737
+ st.error(f"NewsAPI error fetching company news: {e.get_message()}")
738
+ return []
739
+ except Exception as e:
740
+ st.error(f"Unexpected error fetching company news: {str(e)}")
741
+ return []
742
+
743
+ with st.spinner("Fetching news..."):
744
+ gnews_articles = get_gnews_articles()
745
+ job_news = get_indian_job_news()
746
+ tech_news = get_indian_tech_news()
747
+ company_news = get_company_hiring_news()
748
+
749
+ # Job Market News Section (Combining GNews and NewsAPI)
750
+ st.markdown('<h2 class="section-header">Job Market News</h2>', unsafe_allow_html=True)
751
+ if gnews_articles or job_news:
752
+ st.markdown('<div class="grid-container">', unsafe_allow_html=True)
753
+ for article in gnews_articles:
754
+ st.markdown(f"""
755
+ <div class="article-card">
756
+ <h3>{article['title']}</h3>
757
+ <p class="meta">Source: {article['source']} | Published: {article['published_at']}</p>
758
+ <p class="description">{article['description']}</p>
759
+ <a href="{article['url']}" target="_blank">Read more</a>
760
+ </div>
761
+ """, unsafe_allow_html=True)
762
+ for article in job_news:
763
+ st.markdown(f"""
764
+ <div class="article-card">
765
+ <h3>{article['title']}</h3>
766
+ <p class="meta">Source: {article['source']} | Published: {article['published_at']}</p>
767
+ <p class="description">{article['description']}</p>
768
+ <a href="{article['url']}" target="_blank">Read more</a>
769
+ </div>
770
+ """, unsafe_allow_html=True)
771
+ st.markdown('</div>', unsafe_allow_html=True)
772
+ else:
773
+ st.markdown('<p class="no-news">No job market news available at the moment. Please try again later.</p>', unsafe_allow_html=True)
774
+
775
+ # Company Hiring News Section
776
+ st.markdown('<h2 class="section-header">Company Hiring News</h2>', unsafe_allow_html=True)
777
+ if company_news:
778
+ st.markdown('<div class="grid-container">', unsafe_allow_html=True)
779
+ for article in company_news:
780
+ st.markdown(f"""
781
+ <div class="article-card">
782
+ <h3>{article['title']}</h3>
783
+ <p class="meta">Company: {article['company']} | Source: {article['source']} | Published: {article['published_at']}</p>
784
+ <p class="description">{article['description']}</p>
785
+ <a href="{article['url']}" target="_blank">Read more</a>
786
+ </div>
787
+ """, unsafe_allow_html=True)
788
+ st.markdown('</div>', unsafe_allow_html=True)
789
+ else:
790
+ st.markdown('<p class="no-news">No company hiring news available at the moment. Please try again later.</p>', unsafe_allow_html=True)
791
+
792
+ # Tech Industry News Section
793
+ st.markdown('<h2 class="section-header">Tech Industry News</h2>', unsafe_allow_html=True)
794
+ if tech_news:
795
+ st.markdown('<div class="grid-container">', unsafe_allow_html=True)
796
+ for article in tech_news:
797
+ st.markdown(f"""
798
+ <div class="article-card">
799
+ <h3>{article['title']}</h3>
800
+ <p class="meta">Source: {article['source']} | Published: {article['published_at']}</p>
801
+ <p class="description">{article['description']}</p>
802
+ <a href="{article['url']}" target="_blank">Read more</a>
803
+ </div>
804
+ """, unsafe_allow_html=True)
805
+ st.markdown('</div>', unsafe_allow_html=True)
806
+ else:
807
+ st.markdown('<p class="no-news">No tech industry news available at the moment. Please try again later.</p>', unsafe_allow_html=True)
808
+
809
+
810
+ # About Section
811
+ elif page == "About":
812
+ st.title("ℹ️ About CareerBoost")
813
+ logo_path = "logo.ico"
814
+ if os.path.exists(logo_path):
815
+ with open(logo_path, "rb") as f:
816
+ logo_bytes = f.read()
817
+ st.markdown(
818
+ f'<img src="data:image/x-icon;base64,{base64.b64encode(logo_bytes).decode()}" width="150">',
819
+ unsafe_allow_html=True
820
+ )
821
+ else:
822
+ st.warning("Logo file (logo.png) not found. Please upload it to the project directory.")
823
+ st.markdown("""
824
+ **CareerBoost** is here to make your job search easier, smarter, and more successful!
825
+ Powered by AI and designed with you in mind, our platform helps you find jobs, build standout CVs, ace interviews,
826
+ and stay updated on career trends—all in one place.
827
+ """)
828
+
829
+ # Features Section
830
+ st.markdown('<h2 class="section-header">What We Offer</h2>', unsafe_allow_html=True)
831
+ col1, col2 = st.columns(2)
832
+ with col1:
833
+ st.markdown("""
834
+ - **🔍 Job Finding**
835
+ Discover job opportunities across top platforms with personalized filters.
836
+ - **📝 CV Maker**
837
+ Create professional, ATS-friendly CVs tailored to your dream role.
838
+ """)
839
+ with col2:
840
+ st.markdown("""
841
+ - **🎤 Interview Prep**
842
+ Practice with customized questions and expert answers to boost your confidence.
843
+ - **📰 Career Insights**
844
+ Stay ahead with the latest job market trends and industry news.
845
+ """)
846
+
847
+ # Mission Section
848
+ st.markdown('<h2 class="section-header">Our Mission</h2>', unsafe_allow_html=True)
849
+ st.markdown("""
850
+ At CareerBoost, we believe everyone deserves a shot at their dream career.
851
+ Whether you're just starting out, switching paths, or aiming for the top,
852
+ we’re here to provide the tools and support you need to succeed.
853
+ Our goal is to make career growth accessible, inclusive, and stress-free.
854
+ """)
855
+
856
+ # Contact Section
857
+ st.markdown('<h2 class="section-header">Get In Touch</h2>', unsafe_allow_html=True)
858
+ st.markdown("""
859
+ We’d love to hear from you! Whether you have questions, feedback, or just want to chat,
860
+ reach out to us anytime.
861
+ """)
862
+ col1, col2 = st.columns(2)
863
+ with col1:
864
+ st.markdown("""
865
+ - 📧 **Email**: [musabbirmushu@gmail.com](mailto:musabbirmushu@gmail.com)
866
+ - 💼 **LinkedIn**: [CareerBoost LinkedIn](https://www.linkedin.com/in/muhammed-musabbir-km-0302b8212?utm_source=share&utm_campaign=share_via&utm_content=profile&utm_medium=android_appt)
867
+ """)
868
+ with col2:
869
+ st.markdown("""
870
+ - 🌐 **Website**: [www.careerboost.ai](https://omnicipher.onrender.com)
871
+ - ⌨️ **GitHub**: [CareerBoost GitHub](https://github.com/musabbirkm)
872
+ """)
873
+
874
+ # Call-to-Action
875
+ st.markdown('<div style="text-align: center; margin-top: 20px;">', unsafe_allow_html=True)
876
+ if st.button("Start Your Career Journey Now!"):
877
+ st.session_state["page"] = "Home"
878
+ st.experimental_rerun()
879
+ st.markdown('</div>', unsafe_allow_html=True)
logo.ico ADDED

Git LFS Details

  • SHA256: 0499d6b39a331fadc862ee07e1c68fc1e5ac87fa04730493b6a2326358b08736
  • Pointer size: 131 Bytes
  • Size of remote file: 217 kB
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ streamlit==1.29.0
2
+ langchain==0.2.16
3
+ langchain-google-genai==1.0.8
4
+ langchain-community==0.2.16
5
+ duckduckgo-search
6
+ requests==2.28.2
7
+ reportlab==4.0.9
8
+ newsapi-python==0.2.7