Deepak Pant commited on
Commit
c6d9110
Β·
1 Parent(s): c2e4879

Updated poetry setup

Browse files
.devcontainer/devcontainer.json CHANGED
@@ -15,10 +15,7 @@
15
  },
16
  // Use 'postCreateCommand' to run commands after the container is created.
17
  "postCreateCommand": "./.devcontainer/postCreateCommand.sh",
18
- "forwardPorts": [
19
- 7860,
20
- 8000
21
- ],
22
  // Configure tool-specific properties.
23
  "customizations": {
24
  "vscode": {
@@ -37,9 +34,7 @@
37
  "tamasfe.even-better-toml" // TOML
38
  ],
39
  "settings": {
40
- "python.testing.pytestArgs": [
41
- "tests"
42
- ],
43
  "python.testing.unittestEnabled": false,
44
  "python.testing.pytestEnabled": true,
45
  "python.defaultInterpreterPath": "/workspaces/resume-maker-ai-agent/.venv/bin/python",
 
15
  },
16
  // Use 'postCreateCommand' to run commands after the container is created.
17
  "postCreateCommand": "./.devcontainer/postCreateCommand.sh",
18
+ "forwardPorts": [7860, 8000],
 
 
 
19
  // Configure tool-specific properties.
20
  "customizations": {
21
  "vscode": {
 
34
  "tamasfe.even-better-toml" // TOML
35
  ],
36
  "settings": {
37
+ "python.testing.pytestArgs": ["tests"],
 
 
38
  "python.testing.unittestEnabled": false,
39
  "python.testing.pytestEnabled": true,
40
  "python.defaultInterpreterPath": "/workspaces/resume-maker-ai-agent/.venv/bin/python",
Makefile CHANGED
@@ -37,7 +37,7 @@ help: ## Display this help message
37
  # Installation and Setup
38
  # =============================
39
  .PHONY: bake-env
40
- bake-env: clean-env ## Install the poetry environment and set up pre-commit hooks
41
  @echo "πŸš€ Creating virtual environment using pyenv and poetry"
42
  @poetry install --all-extras
43
  @poetry run pre-commit install || true
@@ -84,13 +84,9 @@ lint: ## Run code quality tools
84
  @echo "πŸš€ Linting code with pre-commit"
85
  @poetry run pre-commit run -a
86
  @echo "πŸš€ Static type checking with mypy"
87
- # @echo "πŸš€ Sorting imports with isort"
88
- # @poetry run isort resume_maker_ai_agent/
89
- # @echo "πŸš€ Linting code with Ruff"
90
- # @poetry run ruff format resume_maker_ai_agent/
91
  @poetry run mypy
92
  @echo "πŸš€ Checking for obsolete dependencies with deptry"
93
- @poetry run deptry .
94
  @echo "πŸš€ Checking for security vulnerabilities with bandit"
95
  @poetry run bandit -c pyproject.toml -r resume_maker_ai_agent/ -ll
96
 
@@ -132,7 +128,7 @@ bake-and-publish: bake publish ## Build and publish to PyPI
132
  .PHONY: update
133
  update: ## Update project dependencies
134
  @echo "πŸš€ Updating project dependencies"
135
- @poetry update --all-extras
136
  @poetry run pre-commit install --overwrite
137
  @echo "Dependencies updated successfully"
138
 
@@ -142,7 +138,7 @@ update: ## Update project dependencies
142
  .PHONY: run
143
  run: ## Run the project's main application
144
  @echo "πŸš€ Running the project"
145
- @poetry run streamlit run $(PROJECT_SLUG)/app2.py --server.port 7860
146
 
147
  .PHONY: docs-test
148
  docs-test: ## Test if documentation can be built without warnings or errors
 
37
  # Installation and Setup
38
  # =============================
39
  .PHONY: bake-env
40
+ bake-env: ## Install the poetry environment and set up pre-commit hooks
41
  @echo "πŸš€ Creating virtual environment using pyenv and poetry"
42
  @poetry install --all-extras
43
  @poetry run pre-commit install || true
 
84
  @echo "πŸš€ Linting code with pre-commit"
85
  @poetry run pre-commit run -a
86
  @echo "πŸš€ Static type checking with mypy"
 
 
 
 
87
  @poetry run mypy
88
  @echo "πŸš€ Checking for obsolete dependencies with deptry"
89
+ # @poetry run deptry .
90
  @echo "πŸš€ Checking for security vulnerabilities with bandit"
91
  @poetry run bandit -c pyproject.toml -r resume_maker_ai_agent/ -ll
92
 
 
128
  .PHONY: update
129
  update: ## Update project dependencies
130
  @echo "πŸš€ Updating project dependencies"
131
+ @poetry update
132
  @poetry run pre-commit install --overwrite
133
  @echo "Dependencies updated successfully"
134
 
 
138
  .PHONY: run
139
  run: ## Run the project's main application
140
  @echo "πŸš€ Running the project"
141
+ @poetry run streamlit run $(PROJECT_SLUG)/app.py --server.port 7860
142
 
143
  .PHONY: docs-test
144
  docs-test: ## Test if documentation can be built without warnings or errors
poetry.lock ADDED
The diff for this file is too large to render. See raw diff
 
pyproject.toml CHANGED
@@ -8,8 +8,9 @@ requires-python = ">=3.10,<=3.13"
8
  dependencies = [
9
  "crewai[tools]>=0.86.0,<1.0.0",
10
  "streamlit >=1.41.1",
11
- # "PyPDF2 >=3.0.1",
12
  # "python-docx >=1.1.2",
 
 
13
  ]
14
 
15
  [project.urls]
@@ -82,6 +83,7 @@ module = [
82
  "crewai.*",
83
  "crewai_tools.*",
84
  "bs4.*",
 
85
  "resume_maker_ai_agent.crew",
86
  ]
87
  ignore_missing_imports = true
 
8
  dependencies = [
9
  "crewai[tools]>=0.86.0,<1.0.0",
10
  "streamlit >=1.41.1",
 
11
  # "python-docx >=1.1.2",
12
+ "pypdf (>=5.1.0,<6.0.0)",
13
+ "pysqlite3-binary >=0.5.4",
14
  ]
15
 
16
  [project.urls]
 
83
  "crewai.*",
84
  "crewai_tools.*",
85
  "bs4.*",
86
+ "streamlit.*",
87
  "resume_maker_ai_agent.crew",
88
  ]
89
  ignore_missing_imports = true
resume_maker_ai_agent/app.py CHANGED
@@ -1,53 +1,62 @@
1
- import warnings
2
 
 
 
3
  import streamlit as st
4
 
5
- from resume_maker_ai_agent.services.app_service import search_music
 
6
 
7
- warnings.filterwarnings("ignore", category=SyntaxWarning, module="pysbd")
8
 
 
 
 
9
 
10
- # Set page config
11
- st.set_page_config(page_title="Music Search", page_icon="🎡", layout="wide")
12
 
13
- # App title
14
- st.title("🎡 Music Search Results")
15
 
16
- search_query = st.sidebar.text_input("Enter song name or artist")
 
17
 
18
- if search_query:
19
- # Show loading spinner
20
- with st.spinner("Searching for music..."):
21
- music_data = search_music(search_query)
 
22
 
23
- if music_data is None or len(music_data) == 0:
24
- st.warning("No music found. Please try again.")
 
25
 
26
- for item in music_data:
27
- try:
28
- song_id = item["song_info"]["song_url"].split("/")[-1] # Get unique ID from URL
29
- song_title = item["song_info"]["title"].split(" - ")[0]
30
- musicians = item["song_info"]["musician"]
31
- artists = ", ".join(musicians[:2])
32
- release_date = item["song_info"]["release_date"]
 
33
 
34
- # Display song information in a row
35
- with st.container():
36
- # Create columns
37
- col1, col2, col3, col4 = st.columns([1, 2, 2, 2])
38
 
39
- # Column 1: Image
40
- with col1:
41
- st.image(item["album_image_url"], width=100)
 
 
 
 
 
 
42
 
43
- # Column 2: Title and Artists
44
- with col2:
45
- st.markdown(f"**{song_title}**")
46
- st.markdown(f"*{artists} | {release_date}*")
47
 
48
- # Column 4: Audio Player
49
- with col4:
50
- st.audio(item["song_info"]["downloadable_url"])
51
- except Exception as e:
52
- print(f"An error occurred: {e!s}")
53
- continue
 
1
+ # import PyPDF2
2
 
3
+ # from docx import Document
4
+ # from docx.shared import Inches
5
  import streamlit as st
6
 
7
+ # import tempfile
8
+ from resume_maker_ai_agent.services.app_service import run
9
 
 
10
 
11
+ def main() -> None:
12
+ print("main......")
13
+ st.set_page_config(page_title="Resume Maker AI", page_icon="πŸ“„")
14
 
15
+ st.title("Resume Maker AI")
16
+ st.write("Customize your resume for specific job descriptions using AI")
17
 
18
+ # File upload
19
+ uploaded_file = st.file_uploader("Upload your resume (PDF)", type="pdf")
20
 
21
+ # Job description input
22
+ job_description = st.text_area("Enter the job description:", height=200)
23
 
24
+ if st.button("Customize Resume") and uploaded_file is not None and job_description:
25
+ with st.spinner("Customizing your resume..."):
26
+ try:
27
+ # Customize resume
28
+ customized_resume = run(uploaded_file, job_description)
29
 
30
+ # Display customized resume
31
+ st.subheader("Customized Resume")
32
+ st.write(customized_resume)
33
 
34
+ # Create download button
35
+ # doc_buffer = create_docx(customized_resume)
36
+ # st.download_button(
37
+ # label="Download Customized Resume",
38
+ # data=doc_buffer,
39
+ # file_name="customized_resume.docx",
40
+ # mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
41
+ # )
42
 
43
+ except Exception as e:
44
+ st.error(f"An error occurred: {e!s}")
 
 
45
 
46
+ # Add instructions and tips
47
+ with st.expander("How to use"):
48
+ st.write("""
49
+ 1. Upload your current resume in PDF format
50
+ 2. Paste the job description you're targeting
51
+ 3. Click 'Customize Resume' to generate a tailored version
52
+ 4. Review the customized resume
53
+ 5. Download the result as a Word document
54
+ """)
55
 
56
+ # Footer
57
+ st.markdown("---")
58
+ st.markdown("Built with Streamlit and Crew AI")
 
59
 
60
+
61
+ if __name__ == "__main__":
62
+ main()
 
 
 
resume_maker_ai_agent/app2.py DELETED
@@ -1,64 +0,0 @@
1
- import streamlit as st
2
- # import PyPDF2
3
- import io
4
- # from docx import Document
5
- # from docx.shared import Inches
6
- import openai
7
- # import tempfile
8
-
9
- from resume_maker_ai_agent.services.app_service import run, create_docx
10
-
11
-
12
- def main():
13
- print("main......")
14
- st.set_page_config(page_title="Resume Maker AI", page_icon="πŸ“„")
15
-
16
- st.title("Resume Maker AI")
17
- st.write("Customize your resume for specific job descriptions using AI")
18
-
19
- # File upload
20
- uploaded_file = st.file_uploader("Upload your resume (PDF)", type="pdf")
21
-
22
- # Job description input
23
- job_description = st.text_area("Enter the job description:", height=200)
24
-
25
- if st.button("Customize Resume") and uploaded_file is not None and job_description:
26
- with st.spinner("Customizing your resume..."):
27
- try:
28
- # Customize resume
29
- customized_resume = run(
30
- uploaded_file, job_description)
31
-
32
- # Display customized resume
33
- st.subheader("Customized Resume")
34
- st.write(customized_resume)
35
-
36
- # Create download button
37
- doc_buffer = create_docx(customized_resume)
38
- st.download_button(
39
- label="Download Customized Resume",
40
- data=doc_buffer,
41
- file_name="customized_resume.docx",
42
- mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document"
43
- )
44
-
45
- except Exception as e:
46
- st.error(f"An error occurred: {str(e)}")
47
-
48
- # Add instructions and tips
49
- with st.expander("How to use"):
50
- st.write("""
51
- 1. Upload your current resume in PDF format
52
- 2. Paste the job description you're targeting
53
- 3. Click 'Customize Resume' to generate a tailored version
54
- 4. Review the customized resume
55
- 5. Download the result as a Word document
56
- """)
57
-
58
- # Footer
59
- st.markdown("---")
60
- st.markdown("Built with Streamlit and Crew AI")
61
-
62
-
63
- if __name__ == "__main__":
64
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resume_maker_ai_agent/crew.py CHANGED
@@ -1,9 +1,9 @@
 
 
1
  from crewai import Agent, Crew, Process, Task
2
  from crewai.project import CrewBase, agent, crew, task
3
 
4
- from resume_maker_ai_agent.models.response_models import MusicDetails
5
  from resume_maker_ai_agent.tools.custom_tool import search_tool
6
- import warnings
7
 
8
  warnings.filterwarnings("ignore", category=SyntaxWarning, module="pysbd")
9
 
@@ -25,9 +25,7 @@ class ResumeMakerAIAgent:
25
  :return: An instance of the Agent class
26
  """
27
 
28
- return Agent(config=self.agents_config["job_researcher"],
29
- tools=[search_tool],
30
- verbose=True)
31
 
32
  @agent
33
  def profiler(self) -> Agent:
@@ -39,9 +37,7 @@ class ResumeMakerAIAgent:
39
  :return: An instance of the Agent class
40
  """
41
 
42
- return Agent(config=self.agents_config["profiler"],
43
- tools=[search_tool],
44
- verbose=True)
45
 
46
  @agent
47
  def resume_strategist(self) -> Agent:
@@ -54,9 +50,7 @@ class ResumeMakerAIAgent:
54
  :return: An instance of the Agent class
55
  """
56
 
57
- return Agent(config=self.agents_config["resume_strategist"],
58
- tools=[search_tool],
59
- verbose=True)
60
 
61
  @task
62
  def research_task(self) -> Task:
@@ -68,10 +62,7 @@ class ResumeMakerAIAgent:
68
  :return: An instance of the Task class
69
  """
70
 
71
- return Task(
72
- config=self.tasks_config["research_task"],
73
- async_execution=True
74
- )
75
 
76
  @task
77
  def profile_task(self) -> Task:
@@ -83,13 +74,10 @@ class ResumeMakerAIAgent:
83
  :return: An instance of the Task class
84
  """
85
 
86
- return Task(
87
- config=self.tasks_config["profile_task"],
88
- async_execution=True
89
- )
90
 
91
  @task
92
- def profile_task(self) -> Task:
93
  """
94
  Creates the profile task.
95
 
@@ -100,8 +88,8 @@ class ResumeMakerAIAgent:
100
  """
101
 
102
  return Task(
103
- config=self.tasks_config["profile_task"],
104
- context=[research_task, profile_task],
105
  )
106
 
107
  @crew
 
1
+ import warnings
2
+
3
  from crewai import Agent, Crew, Process, Task
4
  from crewai.project import CrewBase, agent, crew, task
5
 
 
6
  from resume_maker_ai_agent.tools.custom_tool import search_tool
 
7
 
8
  warnings.filterwarnings("ignore", category=SyntaxWarning, module="pysbd")
9
 
 
25
  :return: An instance of the Agent class
26
  """
27
 
28
+ return Agent(config=self.agents_config["job_researcher"], tools=[search_tool], verbose=True)
 
 
29
 
30
  @agent
31
  def profiler(self) -> Agent:
 
37
  :return: An instance of the Agent class
38
  """
39
 
40
+ return Agent(config=self.agents_config["profiler"], tools=[search_tool], verbose=True)
 
 
41
 
42
  @agent
43
  def resume_strategist(self) -> Agent:
 
50
  :return: An instance of the Agent class
51
  """
52
 
53
+ return Agent(config=self.agents_config["resume_strategist"], tools=[search_tool], verbose=True)
 
 
54
 
55
  @task
56
  def research_task(self) -> Task:
 
62
  :return: An instance of the Task class
63
  """
64
 
65
+ return Task(config=self.tasks_config["research_task"], async_execution=True)
 
 
 
66
 
67
  @task
68
  def profile_task(self) -> Task:
 
74
  :return: An instance of the Task class
75
  """
76
 
77
+ return Task(config=self.tasks_config["profile_task"], async_execution=True)
 
 
 
78
 
79
  @task
80
+ def resume_strategy_task(self) -> Task:
81
  """
82
  Creates the profile task.
83
 
 
88
  """
89
 
90
  return Task(
91
+ config=self.tasks_config["resume_strategy_task"],
92
+ context=[self.research_task(), self.profile_task()],
93
  )
94
 
95
  @crew
resume_maker_ai_agent/services/app_service.py CHANGED
@@ -1,18 +1,19 @@
1
- import warnings
2
- import PyPDF2
3
- # from docx import Document
4
- import io
5
 
 
6
  from resume_maker_ai_agent.crew import ResumeMakerAIAgent
7
- from streamlit.runtime.uploaded_file_manager import UploadedFile
8
 
9
 
10
- def _extract_text_from_pdf(pdf_file_path):
11
- """Extract text content from uploaded PDF file."""
12
- pdf_reader = PyPDF2.PdfReader(pdf_file_path)
13
  text = ""
14
- for page in pdf_reader.pages:
15
- text += page.extract_text()
 
 
 
 
 
16
  return text
17
 
18
 
@@ -27,24 +28,24 @@ def run(pdf_file_path: UploadedFile, job_description: str) -> str:
27
  """
28
 
29
  print("Extracting text from PDF")
30
- resume_text = _extract_text_from_pdf(pdf_file_path)
31
 
32
  # Run the crew
33
  print("Running the crew")
34
  inputs = {"resume_text": resume_text, "job_description": job_description}
35
  result = ResumeMakerAIAgent().crew().kickoff(inputs=inputs)
36
 
37
- return result.raw
38
 
39
 
40
- def create_docx(content):
41
- """Create a Word document with the content."""
42
- # doc = Document()
43
- # doc.add_paragraph(content)
44
 
45
- # # Save to bytes buffer
46
- # buffer = io.BytesIO()
47
- # doc.save(buffer)
48
- # buffer.seek(0)
49
- # return buffer
50
- return none
 
1
+ import pypdf
2
+ from streamlit.runtime.uploaded_file_manager import UploadedFile
 
 
3
 
4
+ # from docx import Document
5
  from resume_maker_ai_agent.crew import ResumeMakerAIAgent
 
6
 
7
 
8
+ def read_pdf(uploaded_file: UploadedFile) -> str:
 
 
9
  text = ""
10
+ try:
11
+ pdf_reader = pypdf.PdfReader(uploaded_file)
12
+
13
+ for page in pdf_reader.pages:
14
+ text += page.extract_text()
15
+ except Exception as e:
16
+ print(f"An unexpected error occurred: {e}")
17
  return text
18
 
19
 
 
28
  """
29
 
30
  print("Extracting text from PDF")
31
+ resume_text = read_pdf(pdf_file_path)
32
 
33
  # Run the crew
34
  print("Running the crew")
35
  inputs = {"resume_text": resume_text, "job_description": job_description}
36
  result = ResumeMakerAIAgent().crew().kickoff(inputs=inputs)
37
 
38
+ return str(result.raw)
39
 
40
 
41
+ # def create_docx(content) -> bytes | None:
42
+ # """Create a Word document with the content."""
43
+ # # doc = Document()
44
+ # # doc.add_paragraph(content)
45
 
46
+ # # # Save to bytes buffer
47
+ # # buffer = io.BytesIO()
48
+ # # doc.save(buffer)
49
+ # # buffer.seek(0)
50
+ # # return buffer
51
+ # return None