bourahima-coulibaly commited on
Commit
e8013a0
·
1 Parent(s): 2e85219
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .github/workflows/python-app.yml +45 -0
  2. .streamlit/config.toml +5 -0
  3. .vscode/settings.json +5 -0
  4. CVGenius.egg-info/PKG-INFO +16 -0
  5. CVGenius.egg-info/SOURCES.txt +18 -0
  6. CVGenius.egg-info/dependency_links.txt +1 -0
  7. CVGenius.egg-info/requires.txt +7 -0
  8. CVGenius.egg-info/top_level.txt +3 -0
  9. MANIFEST.in +2 -0
  10. README copy.md +70 -0
  11. __init__.py +0 -0
  12. __pycache__/__init__.cpython-311.pyc +0 -0
  13. __pycache__/app.cpython-311.pyc +0 -0
  14. __pycache__/conftest.cpython-311-pytest-8.2.2.pyc +0 -0
  15. app.py +35 -0
  16. auth/__init__.py +0 -0
  17. auth/__pycache__/__init__.cpython-311.pyc +0 -0
  18. auth/__pycache__/authentification.cpython-311.pyc +0 -0
  19. auth/authentification.py +34 -0
  20. auth/config.yaml +21 -0
  21. configuration/__init__.py +0 -0
  22. configuration/__pycache__/__init__.cpython-311.pyc +0 -0
  23. configuration/__pycache__/config.cpython-311.pyc +0 -0
  24. configuration/config.py +53 -0
  25. conftest.py +0 -0
  26. image.png +0 -0
  27. images/background.jpg +0 -0
  28. images/doc1.png +0 -0
  29. images/doc2.png +0 -0
  30. images/logo.png +0 -0
  31. requirements.txt +12 -0
  32. scr/__init__.py +0 -0
  33. scr/__pycache__/__init__.cpython-311.pyc +0 -0
  34. scr/__pycache__/__init__.cpython-312.pyc +0 -0
  35. scr/__pycache__/documentation.cpython-311.pyc +0 -0
  36. scr/__pycache__/logs.cpython-311.pyc +0 -0
  37. scr/__pycache__/logs.cpython-312.pyc +0 -0
  38. scr/__pycache__/models.cpython-311.pyc +0 -0
  39. scr/__pycache__/models.cpython-312.pyc +0 -0
  40. scr/__pycache__/utils.cpython-311.pyc +0 -0
  41. scr/__pycache__/utils.cpython-312.pyc +0 -0
  42. scr/documentation.py +71 -0
  43. scr/logs.py +46 -0
  44. scr/models.py +243 -0
  45. scr/utils.py +26 -0
  46. setup.py +41 -0
  47. tests/__init__.py +0 -0
  48. tests/__pycache__/__init__.cpython-311.pyc +0 -0
  49. tests/__pycache__/test_app.cpython-311-pytest-8.2.2.pyc +0 -0
  50. tests/__pycache__/test_app.cpython-312-pytest-8.2.1.pyc +0 -0
.github/workflows/python-app.yml ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Python application
2
+
3
+ on:
4
+ push:
5
+ branches: [ "main" ]
6
+ pull_request:
7
+ branches: [ "main" ]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ build:
14
+ runs-on: ubuntu-latest
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Set up Python 3.10
20
+ uses: actions/setup-python@v3
21
+ with:
22
+ python-version: "3.10"
23
+
24
+ - name: Install dependencies
25
+ run: |
26
+ python -m pip install --upgrade pip
27
+ pip install flake8 pytest
28
+ if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
29
+
30
+ - name: Install project in editable mode
31
+ run: |
32
+ pip install -e .
33
+
34
+ - name: Set PYTHONPATH
35
+ run: |
36
+ echo "PYTHONPATH=${{ github.workspace }}" >> $GITHUB_ENV
37
+
38
+ - name: Lint with flake8
39
+ run: |
40
+ flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
41
+ flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
42
+
43
+ - name: Test with pytest
44
+ run: |
45
+ pytest
.streamlit/config.toml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ [theme]
2
+ primaryColor="#ef9462"
3
+ backgroundColor="#e1e2e2"
4
+ secondaryBackgroundColor="#d3d4d4"
5
+ textColor="#080101"
.vscode/settings.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "DockerRun.DisableAutoGenerateConfig": true,
3
+ "taipyStudio.gUI.elementsFilePaths": [],
4
+ "CodeGPT.apiKey": "CodeGPT Plus Beta"
5
+ }
CVGenius.egg-info/PKG-INFO ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.1
2
+ Name: CVGenius
3
+ Version: 0.1.0
4
+ Summary: A comprehensive CV management application
5
+ Home-page: https://github.com/coulibaly-b/CVGenius
6
+ Author: Ibrahim COULIBALY
7
+ Author-email: icoulbi4@gmail.com
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.8
14
+ Classifier: Programming Language :: Python :: 3.7
15
+ Requires-Python: >=3.7
16
+ Provides-Extra: dev
CVGenius.egg-info/SOURCES.txt ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MANIFEST.in
2
+ README.md
3
+ setup.py
4
+ CVGenius.egg-info/PKG-INFO
5
+ CVGenius.egg-info/SOURCES.txt
6
+ CVGenius.egg-info/dependency_links.txt
7
+ CVGenius.egg-info/requires.txt
8
+ CVGenius.egg-info/top_level.txt
9
+ auth/__init__.py
10
+ auth/authentification.py
11
+ auth/config.yaml
12
+ configuration/__init__.py
13
+ configuration/config.py
14
+ scr/__init__.py
15
+ scr/documentation.py
16
+ scr/logs.py
17
+ scr/models.py
18
+ scr/utils.py
CVGenius.egg-info/dependency_links.txt ADDED
@@ -0,0 +1 @@
 
 
1
+
CVGenius.egg-info/requires.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ pytest
2
+ pyyaml
3
+
4
+ [dev]
5
+ pytest-cov
6
+ flake8
7
+ black
CVGenius.egg-info/top_level.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ auth
2
+ configuration
3
+ scr
MANIFEST.in ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ include README.md
2
+ include auth/*.yaml # or any other data files
README copy.md ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: CvGeniusAI
3
+ emoji: 📉
4
+ colorFrom: red
5
+ colorTo: red
6
+ sdk: streamlit
7
+ sdk_version: 1.35.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: apache-2.0
11
+ ---
12
+
13
+ # CV Genius
14
+
15
+ CV Genius est une application web Streamlit utilisant l'IA pour assister les utilisateurs dans leur processus de candidature. Elle offre des fonctionnalités telles que le scoring de CV, la génération de lettres de motivation et l'amélioration de CV.
16
+
17
+ ![Interface de l'application](image.png)
18
+ [Lien vers l'application](https://extia-cvgenius.streamlit.app/)
19
+
20
+ ## Fonctionnalités
21
+
22
+ - Scoring CV/Offre d'emploi
23
+ - Génération de lettre de motivation
24
+ - Amélioration de CV
25
+ - Complétion de mail
26
+
27
+ ## Prérequis
28
+
29
+ - Python 3.8+
30
+ - Dépendances du fichier `requirements.txt`
31
+ - Jeton d'API Hugging Face
32
+
33
+ ## Installation
34
+
35
+ 1. Cloner le dépôt :
36
+
37
+ ```bash
38
+ git clone https://huggingface.co/spaces/bourahima/CvGeniusAI
39
+ ```
40
+
41
+ 2. Installez les dépendances :
42
+
43
+ ```bash
44
+ pip install -r requirements.txt
45
+ ```
46
+
47
+ 3. Configurer le jeton API :
48
+ Créez un fichier `.env` à la racine du projet avec :
49
+
50
+ ```txt
51
+ huggingface_api_key=YOUR_API_TOKEN
52
+ ```
53
+
54
+ ## Utilisation
55
+
56
+ 1. Lancer l'application :
57
+
58
+ ```bash
59
+ streamlit run app.py
60
+ ```
61
+
62
+ 2. Suivre les instructions dans l'interface utilisateur.
63
+
64
+ ## Contribution
65
+
66
+ 1. Forker le dépôt
67
+ 2. Créer une branche (`git checkout -b feature/nouvelle-fonctionnalite`)
68
+ 3. Commiter les changements (`git commit -am 'Ajoute une nouvelle fonctionnalité'`)
69
+ 4. Pousser la branche (`git push origin feature/nouvelle-fonctionnalite`)
70
+ 5. Ouvrir une Pull Request
__init__.py ADDED
File without changes
__pycache__/__init__.cpython-311.pyc ADDED
Binary file (237 Bytes). View file
 
__pycache__/app.cpython-311.pyc ADDED
Binary file (1.65 kB). View file
 
__pycache__/conftest.cpython-311-pytest-8.2.2.pyc ADDED
Binary file (237 Bytes). View file
 
app.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from auth.authentification import authenticate_user
3
+ from ui.navigation.render_navigation import render_navigation
4
+ from ui.home.render_home import render_home
5
+ from ui.infos.render_infos import render_infos
6
+ from ui.todos.render_todos import render_todos
7
+ from configuration.config import setup_page_config
8
+ from scr.documentation import documentations
9
+
10
+
11
+ def main(run_setup=True, test_mode=False):
12
+ if run_setup:
13
+ setup_page_config()
14
+
15
+ is_authenticated = authenticate_user()
16
+
17
+ if test_mode:
18
+ return is_authenticated
19
+
20
+ if is_authenticated:
21
+ documentations()
22
+ selected_page = render_navigation()
23
+
24
+ if selected_page == "Home":
25
+ render_home()
26
+ elif selected_page == "Infos":
27
+ render_infos()
28
+ elif selected_page == "To Do's":
29
+ render_todos()
30
+ else:
31
+ st.error("Authentication failed")
32
+
33
+
34
+ if __name__ == "__main__":
35
+ main()
auth/__init__.py ADDED
File without changes
auth/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (242 Bytes). View file
 
auth/__pycache__/authentification.cpython-311.pyc ADDED
Binary file (1.98 kB). View file
 
auth/authentification.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import streamlit_authenticator as stauth
3
+ import yaml
4
+ from yaml.loader import SafeLoader
5
+
6
+
7
+ def load_config():
8
+ with open('auth/config.yaml') as file:
9
+ config = yaml.load(file, Loader=SafeLoader)
10
+ return config
11
+
12
+
13
+ def authenticate_user():
14
+ config = load_config()
15
+ authenticator = stauth.Authenticate(
16
+ config['credentials'],
17
+ config['cookie']['name'],
18
+ config['cookie']['key'],
19
+ config['cookie']['expiry_days'],
20
+ config['pre-authorized']
21
+ )
22
+
23
+ name, authentication_status, username = authenticator.login()
24
+
25
+ if authentication_status is False:
26
+ st.error('Username/password is incorrect')
27
+ elif authentication_status is None:
28
+ st.warning('Please enter your username and password')
29
+ elif authentication_status:
30
+ authenticator.logout('Logout', 'sidebar')
31
+ st.sidebar.markdown(f"Bienvenue, {name} ! 👋")
32
+ return True
33
+
34
+ return False
auth/config.yaml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ credentials:
2
+ usernames:
3
+ jsmith:
4
+ email: jsmith@gmail.com
5
+ failed_login_attempts: 0 # Will be managed automatically
6
+ logged_in: False # Will be managed automatically
7
+ name: John Smith
8
+ password: abc # Will be hashed automatically
9
+ rbriggs:
10
+ email: rbriggs@gmail.com
11
+ failed_login_attempts: 0 # Will be managed automatically
12
+ logged_in: False # Will be managed automatically
13
+ name: Rebecca Briggs
14
+ password: def # Will be hashed automatically
15
+ cookie:
16
+ expiry_days: 30
17
+ key: some_signature_key # Must be string
18
+ name: some_cookie_name
19
+ pre-authorized:
20
+ emails:
21
+ - melsby@gmail.com
configuration/__init__.py ADDED
File without changes
configuration/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (251 Bytes). View file
 
configuration/__pycache__/config.cpython-311.pyc ADDED
Binary file (1.92 kB). View file
 
configuration/config.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from PIL import Image
3
+ import os
4
+
5
+
6
+ def setup_page_config():
7
+ logo_path = os.path.join(os.getcwd(), "images", "logo.png")
8
+ logo = Image.open(logo_path)
9
+
10
+ st.set_page_config(
11
+ page_title="CV Genius",
12
+ page_icon=logo,
13
+ initial_sidebar_state="collapsed",
14
+ layout='wide'
15
+ )
16
+
17
+ # Add CSS styles
18
+ st.markdown("""
19
+ <style>
20
+ .title {
21
+ font-size: 36px;
22
+ font-weight: bold;
23
+ color: #2D3E50;
24
+ }
25
+ .subtitle {
26
+ font-size: 24px;
27
+ font-weight: bold;
28
+ color: #4A6F8A;
29
+ }
30
+ .description {
31
+ font-size: 18px;
32
+ color: #6C8798;
33
+ }
34
+ </style>
35
+ """, unsafe_allow_html=True)
36
+
37
+
38
+ def get_over_theme():
39
+ return {
40
+ "txc_inactive": "#FFFFFF",
41
+ "color": "#FF6300",
42
+ "txc_active": "#2D3E50",
43
+ "MENU_BACKGROUND": "#FF6300",
44
+ "txc_hover": "#4A6F8A",
45
+ "MENU_BACKGROUND_HOVER": "#4A6F8A",
46
+ }
47
+
48
+
49
+ def get_menu_data():
50
+ return [
51
+ {"id": "Infos", "icon": "💡", "label": "Infos"},
52
+ {"icon": "🚀", "label": "To Do's"},
53
+ ]
conftest.py ADDED
File without changes
image.png ADDED
images/background.jpg ADDED
images/doc1.png ADDED
images/doc2.png ADDED
images/logo.png ADDED
requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ streamlit==1.36.0
2
+ streamlit-pills==0.3.0
3
+ langchain==0.2.9
4
+ langchain-community==0.2.7
5
+ langchain-huggingface==0.0.3
6
+ pdfminer-six==20231228
7
+ streamlit-aggrid==0.2.2-2
8
+ reportlab==4.2.2
9
+ hydralit==1.0.14
10
+ python-dotenv
11
+ werkzeug==3.0.3
12
+ streamlit-authenticator==0.3.2
scr/__init__.py ADDED
File without changes
scr/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (241 Bytes). View file
 
scr/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (209 Bytes). View file
 
scr/__pycache__/documentation.cpython-311.pyc ADDED
Binary file (4.67 kB). View file
 
scr/__pycache__/logs.cpython-311.pyc ADDED
Binary file (2.6 kB). View file
 
scr/__pycache__/logs.cpython-312.pyc ADDED
Binary file (4.86 kB). View file
 
scr/__pycache__/models.cpython-311.pyc ADDED
Binary file (12.4 kB). View file
 
scr/__pycache__/models.cpython-312.pyc ADDED
Binary file (13 kB). View file
 
scr/__pycache__/utils.cpython-311.pyc ADDED
Binary file (1.74 kB). View file
 
scr/__pycache__/utils.cpython-312.pyc ADDED
Binary file (1.44 kB). View file
 
scr/documentation.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from PIL import Image
3
+ import os
4
+
5
+
6
+ def documentations():
7
+ st.sidebar.image(Image.open(
8
+ os.path.join(os.getcwd(),
9
+ "images",
10
+ "background.jpg"
11
+ )
12
+ )
13
+ )
14
+
15
+ st.sidebar.markdown(
16
+ "<div class='title'>CV Genius</div>", unsafe_allow_html=True
17
+ )
18
+ st.sidebar.markdown(
19
+ "<div class='subtitle'>Améliorez votre processus de candidature</div>",
20
+ unsafe_allow_html=True,
21
+ )
22
+ st.sidebar.markdown(
23
+ """<div class='description'>Cette application utilise des modèles d'IA
24
+ pour vous aider à scorer votre CV, rédiger des lettres de motivation et
25
+ améliorer votre CV.</div>""",
26
+ unsafe_allow_html=True,
27
+ )
28
+ with st.sidebar.expander("Documentation", expanded=True):
29
+ st.write("""Welcome to the documentation page for our project.
30
+ Here you will find all the necessary information to get
31
+ started with the Hugging Face API and Streamlit settings.
32
+ """)
33
+
34
+ st.header("Hugging Face Access Key")
35
+ st.write("""To use the Hugging Face API, you need to obtain an
36
+ access key. Follow these steps to get your key:""")
37
+ st.markdown(
38
+ """
39
+ 1. Go to the [Hugging Face website](https://huggingface.co/).
40
+ """)
41
+ st.markdown("""
42
+ 2. Sign up for an account if you don't have one already.
43
+ """)
44
+ st.markdown("3. Once logged in, go to your profile settings.")
45
+ st.markdown("4. Look for the 'Access Tokens' section.")
46
+ st.markdown("5. Generate a new access token and copy it.")
47
+ st.markdown("""
48
+ <a href=https://huggingface.co/docs/hub/security-tokens>
49
+ For more information</a>""", unsafe_allow_html=True)
50
+
51
+ st.header("Setting Hugging Face Access Key in Streamlit")
52
+ st.write("""To use the Hugging Face API in your Streamlit app,
53
+ you need to set the access key as an environment
54
+ variable. Follow these steps:""")
55
+ st.markdown("1. Open your application.")
56
+ st.markdown("""2. At the bottom of your Streamlit app, click
57
+ on the manage app button, then select the 3 horizontal
58
+ dots, go to the settings, and select 'secrets' to
59
+ replace the new access key.""")
60
+
61
+ # Load and display images
62
+ doc1_path = os.path.join(os.getcwd(), "images", "doc1.png")
63
+ doc1 = Image.open(doc1_path)
64
+ st.image(doc1, caption="Manage app", use_column_width=True)
65
+
66
+ doc2_path = os.path.join(os.getcwd(), "images", "doc2.png")
67
+ doc2 = Image.open(doc2_path)
68
+ st.image(doc2, caption="Manage app", use_column_width=True)
69
+
70
+ st.write("""Now you can use the Hugging Face API in your
71
+ Streamlit app without any issues.""")
scr/logs.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import streamlit as st
3
+ from werkzeug.security import generate_password_hash, check_password_hash
4
+
5
+
6
+ USERS_FILE = "users.json"
7
+
8
+
9
+ def load_users():
10
+ try:
11
+ with open(USERS_FILE, "r") as f:
12
+ content = f.read().strip()
13
+ if content:
14
+ return json.loads(content)
15
+ else:
16
+ return {}
17
+ except (FileNotFoundError, json.JSONDecodeError):
18
+ return {}
19
+
20
+
21
+ def save_users(users):
22
+ with open(USERS_FILE, "w") as f:
23
+ json.dump(users, f)
24
+
25
+
26
+ def add_user(username, password):
27
+ users = load_users()
28
+ if username in users:
29
+ return False
30
+ hashed_password = generate_password_hash(password)
31
+ users[username] = hashed_password
32
+ save_users(users)
33
+ return True
34
+
35
+
36
+ def check_credentials(username, password):
37
+ users = load_users()
38
+ if username not in users:
39
+ return False
40
+ return check_password_hash(users[username], password)
41
+
42
+
43
+ def logout():
44
+ st.session_state.logged_in = False
45
+ st.session_state.username = None
46
+ st.rerun() # Recharger l'application pour refléter les changements
scr/models.py ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_huggingface.llms import HuggingFaceEndpoint
2
+ from langchain_core.prompts import PromptTemplate
3
+
4
+ from requests.exceptions import HTTPError
5
+ import streamlit as st
6
+ from scr.utils import ModelError
7
+ from abc import ABC, abstractmethod
8
+
9
+ import os
10
+ from dotenv import load_dotenv
11
+
12
+ load_dotenv()
13
+
14
+
15
+ HUGGINGFACE_HUB_API_TOKEN = os.getenv("huggingface_api_key")
16
+
17
+
18
+ class ResumeAIStrategy(ABC):
19
+
20
+ def __init__(self):
21
+ self.llm = HuggingFaceEndpoint(
22
+ repo_id="mistralai/MixTraL-8x7B-Instruct-v0.1",
23
+ temperature=0.001,
24
+ repetition_penalty=1.2,
25
+ max_length=10000,
26
+ max_new_tokens=2000,
27
+ huggingfacehub_api_token=HUGGINGFACE_HUB_API_TOKEN,
28
+ add_to_git_credential=True,
29
+ )
30
+
31
+ @abstractmethod
32
+ def generate(self, resume: str, job_advert: str) -> str:
33
+ pass
34
+
35
+
36
+ class ScoreResumeJob(ResumeAIStrategy):
37
+ def __init__(self):
38
+ super().__init__()
39
+
40
+ def generate(self, resume: str, job_advert: str) -> str:
41
+ prompt = """Évaluez la correspondance entre le CV d'un candidat et
42
+ la description du poste en attribuant un score sur 100. Tenez compte
43
+ des éléments suivants par ordre d'importance :
44
+
45
+ 1. Dernière expérience professionnelle et sa durée
46
+ 2. Deuxième expérience professionnelle et sa durée
47
+ 3. Présence de lacunes dans le parcours professionnel
48
+ 4. Formations, certifications et renommée des institutions
49
+ 5. Technologies maîtrisées
50
+ 6. Projets réalisés
51
+ 7. Engagement dans des actions humanitaires
52
+
53
+ Notez que la maîtrise d'un langage de programmation implique la
54
+ connaissance des librairies et frameworks associés. Répondez
55
+ au format suivant :
56
+
57
+ - Score de correspondance : [Score sur 100]
58
+ - Points forts : [Liste des principaux points forts du candidat]
59
+ - Points faibles : [Liste des principaux points faibles du candidat]
60
+ - Explication : [Paragraphe expliquant le score, les points forts
61
+ et faibles]
62
+
63
+ Exemple :
64
+ Score de correspondance : 85/100
65
+ Points forts :
66
+ - Expérience de 5 ans dans un rôle similaire
67
+ - Maîtrise des technologies requises
68
+ - Formation pertinente
69
+
70
+ Points faibles :
71
+ - Manque d'expérience avec un outil spécifique
72
+ - Absence de certifications professionnelles
73
+
74
+ Explication : Le candidat est bien qualifié avec une solide expérience
75
+ et des compétences pertinentes, bien que quelques domaines nécessitent
76
+ des améliorations.
77
+
78
+ CV : {resume}
79
+ Description du poste : {job_advert}
80
+ Réponse :"""
81
+
82
+ prompt_template = PromptTemplate(
83
+ template=prompt, input_variables=["resume", "job_advert"]
84
+ )
85
+ chain = prompt_template | self.llm
86
+ result = chain.invoke({"resume": resume, "job_advert": job_advert})
87
+ return result
88
+
89
+
90
+ class CoverLetterGenerator(ResumeAIStrategy):
91
+ def __init__(self):
92
+ super().__init__()
93
+
94
+ def generate(self, resume: str, job_advert: str) -> str:
95
+ prompt = """Générez une lettre de motivation professionnelle pour le
96
+ poste décrit ci-dessous, en vous basant sur le CV fourni. La lettre
97
+ doit inclure :
98
+
99
+ 1. Une introduction accrocheuse
100
+ 2. Vos expériences et compétences pertinentes pour le poste, en
101
+ utilisant des termes techniques spécifiques et des exemples
102
+ concrets de réalisations
103
+ 3. Votre motivation pour le poste et l'entreprise
104
+ 4. Une conclusion avec un appel à l'action
105
+
106
+ CV : {resume}
107
+ Description du poste : {job_advert}
108
+
109
+ Réponse :"""
110
+
111
+ prompt_template = PromptTemplate(
112
+ template=prompt, input_variables=["resume", "job_advert"]
113
+ )
114
+ chain = prompt_template | self.llm
115
+ result = chain.invoke({"resume": resume, "job_advert": job_advert})
116
+ return result.replace('`', '')
117
+
118
+
119
+ class ResumeImprover(ResumeAIStrategy):
120
+ def __init__(self):
121
+ super().__init__()
122
+
123
+ def generate(self, resume: str, job_advert: str) -> str:
124
+ prompt = """Améliorez le CV ci-dessous en mettant en avant les
125
+ compétences, qualifications et expériences pertinentes pour
126
+ le poste. L'objectif est d'obtenir un score de correspondance
127
+ supérieur à 95%.
128
+
129
+ Instructions :
130
+ - Résumé : Présentez brièvement le candidat en mettant en avant ses
131
+ forces principales et sa pertinence pour le poste, en utilisant
132
+ des mots-clés de l'offre.
133
+ - Compétences : Listez les compétences les plus pertinentes pour le
134
+ poste, en mettant en avant celles mentionnées dans l'offre d'emploi.
135
+ - Expérience professionnelle : Réorganisez et reformulez les
136
+ expériences pour souligner les réalisations pertinentes pour le
137
+ poste. Combinez les points si n��cessaire.
138
+ - Formation et certifications : Mettez en avant les formations et
139
+ certifications pertinentes, ajoutant des informations manquantes
140
+ si nécessaire.
141
+ - Projets : Reformulez et mettez en avant les projets pertinents,
142
+ incluant des projets open source valorisants si nécessaire.
143
+ - Informations supplémentaires : Ajoutez toute information valorisante
144
+ comme les implications bénévoles, récompenses, publications, etc.
145
+
146
+ Assurez-vous que les modifications sont professionnelles, concises
147
+ et positives. La structure du CV doit être cohérente et logique.
148
+
149
+ CV : {resume}
150
+ Offre d'emploi : {job_advert}
151
+
152
+ Contexte supplémentaire : Le candidat a une vaste expérience non
153
+ listée qui pourrait être pertinente pour le poste. Veuillez en
154
+ tenir compte.
155
+
156
+ Réponse :"""
157
+
158
+ prompt_template = PromptTemplate(
159
+ template=prompt, input_variables=["resume", "job_advert"]
160
+ )
161
+ chain = prompt_template | self.llm
162
+ result = chain.invoke({"resume": resume, "job_advert": job_advert})
163
+ return result
164
+
165
+
166
+ class ResumeGenerator:
167
+ def __init__(self, resume: str,
168
+ job_advert: str,
169
+ resumeStrategy: ResumeAIStrategy):
170
+ self.resume = resume
171
+ self.job_advert = job_advert
172
+ self.resumeStrategy = resumeStrategy
173
+
174
+ def generator(self) -> str:
175
+ try:
176
+ generated_text = self.resumeStrategy.generate(
177
+ resume=self.resume, job_advert=self.job_advert
178
+ )
179
+ return generated_text
180
+ except TimeoutError:
181
+ return """Le modèle a pris trop de temps pour répondre.
182
+ Veuillez réessayer plus tard."""
183
+ except ModelError as e:
184
+ return f"""Une erreur s'est produite lors de l'appel
185
+ au modèle : {str(e)}"""
186
+ except HTTPError as http_err:
187
+ if http_err.response.status_code == 500:
188
+ request_id = http_err.response.headers.get("x-request-id",
189
+ "N/A")
190
+ return f"""API problem: Internal Server Error
191
+ (Request ID: {request_id})"""
192
+ else:
193
+ return f"HTTP error occurred: {http_err}"
194
+ except Exception as e:
195
+ return f"Une erreur inattendue s'est produite : {str(e)}"
196
+
197
+
198
+ class MailCompletion:
199
+ def __init__(self):
200
+ self.llm = HuggingFaceEndpoint(
201
+ repo_id="mistralai/MixTraL-8x7B-Instruct-v0.1",
202
+ temperature=0.001,
203
+ max_new_tokens=1000,
204
+ huggingfacehub_api_token=HUGGINGFACE_HUB_API_TOKEN,
205
+ )
206
+
207
+ def mailcompletion(self, resume: str) -> str:
208
+ prompt = """Complétez le modèle de courrier électronique ci-dessous en
209
+ utilisant les informations du CV fourni. Remplacez les parties entre
210
+ crochets [] par les informations pertinentes du CV.
211
+
212
+ Format :
213
+ Bonjour,
214
+
215
+ J'espère que vous allez bien.
216
+
217
+ Je vous propose le profil de [Prénom du candidat], [Intitulé du poste]
218
+ avec [Nombre] année(s) d'expérience qui pourrait intéresser votre
219
+ équipe.
220
+
221
+ Vous trouverez son dossier technique en pièce jointe.
222
+
223
+ En quelques mots :
224
+ - Technologies & Langages : [Liste des technologies et langages de
225
+ programmation]
226
+ - Compétences métiers : [Liste des compétences métiers pertinentes]
227
+ - Dernier client : [Nom de l'entreprise de la dernière expérience]
228
+ - Disponibilité : [Date de disponibilité ou Immédiatement]
229
+
230
+ Qu'en pensez-vous ? Je reste à votre disposition pour toute
231
+ information complémentaire.
232
+
233
+ Excellente journée,
234
+
235
+ CV : {resume}
236
+
237
+ Réponse :"""
238
+
239
+ prompt_template = PromptTemplate(template=prompt,
240
+ input_variables=["resume"])
241
+ chain = prompt_template | self.llm
242
+ result = chain.invoke({"resume": resume})
243
+ return result
scr/utils.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pdfminer.high_level import extract_text
2
+ from io import BytesIO
3
+
4
+ from reportlab.lib.pagesizes import letter
5
+ from reportlab.platypus import SimpleDocTemplate, Paragraph
6
+ from reportlab.lib.styles import getSampleStyleSheet
7
+
8
+
9
+ def extract_text_from_pdf(pdf_path):
10
+ return extract_text(pdf_path)
11
+
12
+
13
+ def generate_pdf(text):
14
+ styles = getSampleStyleSheet()
15
+ pdf_buffer = BytesIO()
16
+ doc = SimpleDocTemplate(pdf_buffer, pagesize=letter)
17
+ elements = []
18
+ for line in text.split('\n'):
19
+ elements.append(Paragraph(line, styles['BodyText']))
20
+ doc.build(elements)
21
+ pdf_buffer.seek(0)
22
+ return pdf_buffer
23
+
24
+
25
+ class ModelError(Exception):
26
+ pass
setup.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name='CVGenius',
5
+ version='0.1.0',
6
+ description='A comprehensive CV management application',
7
+ author='Ibrahim COULIBALY',
8
+ author_email='icoulbi4@gmail.com',
9
+ url='https://github.com/coulibaly-b/CVGenius',
10
+ packages=find_packages(exclude=['tests*']),
11
+ include_package_data=True,
12
+ install_requires=[
13
+ 'pytest',
14
+ 'pyyaml',
15
+ # Add other dependencies here
16
+ ],
17
+ extras_require={
18
+ 'dev': [
19
+ 'pytest-cov',
20
+ 'flake8',
21
+ 'black',
22
+ # Add other development dependencies here
23
+ ],
24
+ },
25
+ entry_points={
26
+ 'console_scripts': [
27
+ # If you have any scripts to run
28
+ # 'script_name = module:function',
29
+ ],
30
+ },
31
+ classifiers=[
32
+ 'Development Status :: 3 - Alpha', # Adjust as appropriate
33
+ 'Intended Audience :: Developers',
34
+ 'License :: OSI Approved :: MIT License', # Adjust if different
35
+ 'Programming Language :: Python :: 3.10',
36
+ 'Programming Language :: Python :: 3.9',
37
+ 'Programming Language :: Python :: 3.8',
38
+ 'Programming Language :: Python :: 3.7',
39
+ ],
40
+ python_requires='>=3.7',
41
+ )
tests/__init__.py ADDED
File without changes
tests/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (243 Bytes). View file
 
tests/__pycache__/test_app.cpython-311-pytest-8.2.2.pyc ADDED
Binary file (6.35 kB). View file
 
tests/__pycache__/test_app.cpython-312-pytest-8.2.1.pyc ADDED
Binary file (1.18 kB). View file