Skip to content

Commit 6945805

Browse files
authored
Merge 5a4bbee into f0b23b2
2 parents f0b23b2 + 5a4bbee commit 6945805

File tree

9 files changed

+76
-39
lines changed

9 files changed

+76
-39
lines changed

.github/workflows/ci_e2e.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
pnpm i
4141
pnpm lint
4242
pnpm build
43-
pnpm run dev &
43+
pnpm preview &
4444
4545
# Step 3: Start BE
4646
- name: Set up and start backend
@@ -52,7 +52,7 @@ jobs:
5252
# Step 4: Wair for BE and FE Services
5353
- name: Wait for services to be ready
5454
run: |
55-
until curl -s http://localhost:3001; do
55+
until curl -s http://localhost:8081; do
5656
echo "Waiting for frontend to be ready..."
5757
sleep 5
5858
done

be_repo/app.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@
66
from google.auth.transport import requests as google_requests
77
from google.oauth2 import id_token
88

9-
from configs.database import get_resume_database, get_user_database
9+
from configs.database import get_resume_database, get_user_database, get_key_database
1010
from graphs.qa_graph import create_graph
1111
from modules.evaluator import evaluate_resume, evaluate_resume_with_jd
1212
from modules.job_recommendation_system import job_recommend
1313
from modules.langgraph_qa import get_answer_from_langgraph
1414
from modules.upload import upload_parse_resume
1515

16+
keys_db = get_key_database()
17+
keys_collection = keys_db["keys"]
18+
GOOGLE_CLIENT_ID = keys_collection.find_one({"_id": "google_api"})["api_key"]
19+
1620
# Generate a secure random secret key
1721
secret_key = secrets.token_hex(32) # Generates a 64-character hexadecimal string
1822

@@ -27,8 +31,6 @@
2731
PERMANENT_SESSION_LIFETIME=timedelta(minutes=30),
2832
)
2933

30-
GOOGLE_CLIENT_ID = '120137358324-l62fq2hlj9r31evvitg55rcl4rf21udd.apps.googleusercontent.com'
31-
3234
# Test MongoDB connection
3335
try:
3436
resume_database = get_resume_database()
@@ -190,19 +192,19 @@ def interview_question_suggestion():
190192
3. What technologies and tools are used in the project.
191193
4. What technologies and tools are used to acquire the certification and awards.
192194
5. Work experience in the field of technology (if any).
193-
195+
194196
Your response should be structured as follows, using the information you get from the resume:
195197
The idea you get the following questions, such as the project, technologies used, certification and awards:
196198
1. Question 1
197199
2. Question 2
198200
3. ...
199-
201+
200202
For example, you can make suggestions like:
201203
AWS related questions:
202204
1. How do you use AWS services in your project?
203205
2. What do you know about AWS?
204206
3. What is the structure of your AWS environment?
205-
207+
206208
Replace the questions with your own based on the information you get from the resume.
207209
Follow this format for all categories of questions.
208210
Your response should contain only categorized questions. Do not include unrelated information.

be_repo/modules/job_recommendation_system.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@
77
from .resume_processor import ResumeProcessor
88
from .retrieval_engine import RetrievalEngine
99
from .view import CLIView
10+
from configs.database import get_key_database
11+
12+
keys_db = get_key_database()
13+
keys_collection = keys_db["keys"]
14+
15+
# Neo4j Connection Details
16+
NEO4J_URI = keys_collection.find_one({"_id": "NEO4J_URI"})["api_key"] # Replace with your Neo4j URI
17+
NEO4J_USERNAME = "neo4j" # Replace with your Neo4j username
18+
NEO4J_PASSWORD = keys_collection.find_one({"_id": "NEO4J_PASSWORD"})["api_key"] # Replace with your Neo4j password
1019

1120

1221
def job_recommend(resume_text, user_id):
@@ -19,11 +28,6 @@ def job_recommend(resume_text, user_id):
1928
logger.error(f'No resume text provided, user_id: {user_id}.')
2029
return 'Error: No resume text provided.'
2130

22-
# Neo4j Connection Details
23-
NEO4J_URI = "neo4j+ssc://7bf5a48e.databases.neo4j.io" # Replace with your Neo4j URI
24-
NEO4J_USERNAME = "neo4j" # Replace with your Neo4j username
25-
NEO4J_PASSWORD = "oxsK7V5_86emZlYQlvCfQHfVWS95wXz29OhtU8GAdFc" # Replace with your Neo4j password
26-
2731
# Initialize Model
2832
neo4j_model = Neo4jModel(
2933
uri=NEO4J_URI,

be_repo/modules/langgraph_qa.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ def get_answer_from_langgraph(qa_graph, resume_text, user_state_collection, user
2323
events = qa_graph.stream(
2424
{"messages": [("user", question)]}, config, stream_mode="values"
2525
)
26+
final_result = ''
2627
for event in events:
2728
if event["messages"][-1].type == "ai":
28-
return event["messages"][-1].content
29+
final_result = event["messages"][-1].content
2930

30-
return
31+
return final_result

be_repo/modules/retrieval_engine.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
# retrieval_engine.py
22

3-
from langchain.chains.combine_documents import create_stuff_documents_chain
3+
from langchain_neo4j import GraphCypherQAChain
4+
from langchain_openai import ChatOpenAI
45
from langchain.chains.retrieval import create_retrieval_chain
6+
from langchain.chains.combine_documents import create_stuff_documents_chain
7+
from configs.openai_key import get_openai_api_key # New import
58
from langchain.prompts import PromptTemplate
69

7-
810
class RetrievalEngine:
911
def __init__(self, resume_processor, neo4j_model):
1012
"""

be_repo/modules/verify.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
from neo4j import GraphDatabase
2+
from configs.database import get_key_database
23

3-
uri = "neo4j+ssc://7bf5a48e.databases.neo4j.io" # Update with your Neo4j URI
4-
username = "neo4j" # Update with your username
5-
password = "oxsK7V5_86emZlYQlvCfQHfVWS95wXz29OhtU8GAdFc" # Update with your password
4+
keys_db = get_key_database()
5+
keys_collection = keys_db["keys"]
6+
7+
# Neo4j Connection Details
8+
NEO4J_URI = keys_collection.find_one({"_id": "NEO4J_URI"})["api_key"] # Replace with your Neo4j URI
9+
NEO4J_USERNAME = "neo4j" # Replace with your Neo4j username
10+
NEO4J_PASSWORD = keys_collection.find_one({"_id": "NEO4J_PASSWORD"})["api_key"] # Replace with your Neo4j password
11+
12+
uri = NEO4J_URI # Update with your Neo4j URI
13+
username = NEO4J_USERNAME # Update with your username
14+
password = NEO4J_PASSWORD # Update with your password
615

716
driver = GraphDatabase.driver(uri, auth=(username, password))
817

be_repo/modules/view.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ def display_recommendations(self, recommendations):
2828
Display job recommendations to the user.
2929
"""
3030
if not recommendations:
31-
return 'No job recommendations found based on your resume.'
32-
res = '\nRecommended Jobs for You:\n'
31+
return "No job recommendations found based on your resume."
32+
res = "\nRecommended Jobs for You:\n"
3333
for idx, job in enumerate(recommendations, start=1):
34-
res += f'{idx}. {job}\n'
34+
res += f"{idx}. {job}\n"
3535
return res

be_repo/preprocess/neo4j_import.py

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@
66
import os
77
from tqdm import tqdm
88
import logging
9+
from configs.database import get_key_database
10+
11+
keys_db = get_key_database()
12+
keys_collection = keys_db["keys"]
13+
14+
# Neo4j Connection Details
15+
NEO4J_URI = keys_collection.find_one({"_id": "NEO4J_URI"})["api_key"] # Replace with your Neo4j URI
16+
NEO4J_USERNAME = "neo4j" # Replace with your Neo4j username
17+
NEO4J_PASSWORD = keys_collection.find_one({"_id": "NEO4J_PASSWORD"})["api_key"] # Replace with your Neo4j password
918

1019
# Configure logging
1120
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@@ -29,8 +38,8 @@
2938
}
3039

3140
# Neo4j connection details from environment variables
32-
uri = "neo4j+ssc://7bf5a48e.databases.neo4j.io"
33-
AUTH = ("neo4j", "oxsK7V5_86emZlYQlvCfQHfVWS95wXz29OhtU8GAdFc")
41+
uri = NEO4J_URI
42+
AUTH = (NEO4J_USERNAME, NEO4J_PASSWORD)
3443

3544
# Initialize Neo4j driver
3645
driver = GraphDatabase.driver(uri, auth=AUTH)
@@ -44,6 +53,7 @@
4453
driver.close()
4554
exit(1)
4655

56+
4757
# Function to load node CSV files into DataFrames
4858
def load_node_dataframes(csv_dir, node_types):
4959
node_dfs = {}
@@ -57,6 +67,7 @@ def load_node_dataframes(csv_dir, node_types):
5767
logger.warning(f"CSV file for node type '{node_type}' not found in '{csv_dir}'.")
5868
return node_dfs
5969

70+
6071
# Function to load relationships CSV file into a DataFrame
6172
def load_relationships_data(csv_dir):
6273
relationships_file = os.path.join(csv_dir, 'relationships.csv')
@@ -68,6 +79,7 @@ def load_relationships_data(csv_dir):
6879
logger.warning(f"Relationships CSV file not found in '{csv_dir}'.")
6980
return None
7081

82+
7183
# Function to create constraints
7284
def create_constraints(driver):
7385
constraints = [
@@ -91,12 +103,15 @@ def create_constraints(driver):
91103
logger.error(f"Failed to execute constraint '{constraint}': {e}")
92104
logger.info("Constraints created or already exist.")
93105

106+
94107
def standardize_relationship_types(df):
95108
if 'relationship_type' in df.columns:
96109
original_types = df['relationship_type'].unique()
97-
df['relationship_type'] = df['relationship_type'].str.upper().str.replace(' ', '_').str.replace('[^A-Z0-9_]', '', regex=True)
110+
df['relationship_type'] = df['relationship_type'].str.upper().str.replace(' ', '_').str.replace('[^A-Z0-9_]',
111+
'', regex=True)
98112
standardized_types = df['relationship_type'].unique()
99-
logger.info(f"Standardized relationship types from {len(original_types)} to {len(standardized_types)} unique types.")
113+
logger.info(
114+
f"Standardized relationship types from {len(original_types)} to {len(standardized_types)} unique types.")
100115
return df
101116

102117

@@ -116,12 +131,13 @@ def import_nodes_in_batches(tx, node_type, df, batch_size=1000):
116131
df['embedding'] = df['embedding'].apply(lambda x: json.loads(x) if pd.notnull(x) else [])
117132
data = df.to_dict('records')
118133
for i in tqdm(range(0, len(data), batch_size), desc=f"Importing {node_type} in batches"):
119-
batch = data[i:i+batch_size]
134+
batch = data[i:i + batch_size]
120135
try:
121136
tx.run(query, rows=batch)
122-
logger.info(f"Imported batch {i//batch_size + 1} for node type '{node_type}'.")
137+
logger.info(f"Imported batch {i // batch_size + 1} for node type '{node_type}'.")
123138
except Exception as e:
124-
logger.error(f"Error importing batch {i//batch_size + 1} for node type '{node_type}': {e}")
139+
logger.error(f"Error importing batch {i // batch_size + 1} for node type '{node_type}': {e}")
140+
125141

126142
# Function to create a mapping from ID to node type
127143
def create_id_to_type_mapping(node_dfs):
@@ -135,6 +151,7 @@ def create_id_to_type_mapping(node_dfs):
135151
logger.info("Created ID to node type mapping.")
136152
return id_to_type
137153

154+
138155
# Function to infer node types for relationships
139156
def infer_node_types(rel_df, id_to_type):
140157
rel_df['start_node_type'] = rel_df['start_node_id'].apply(lambda x: id_to_type.get(int(x), 'Unknown'))
@@ -149,10 +166,11 @@ def infer_node_types(rel_df, id_to_type):
149166
logger.warning(unknown_end)
150167
return rel_df
151168

169+
152170
def import_relationships_in_batches(tx, df, batch_size=1000):
153171
data = df.to_dict('records')
154172
for i in tqdm(range(0, len(data), batch_size), desc="Importing relationships in batches"):
155-
batch = data[i:i+batch_size]
173+
batch = data[i:i + batch_size]
156174
unwind_data = [
157175
{
158176
"start_id": int(rel['start_node_id']),
@@ -170,9 +188,9 @@ def import_relationships_in_batches(tx, df, batch_size=1000):
170188
"""
171189
try:
172190
tx.run(query, rows=unwind_data)
173-
logger.info(f"Imported batch {i//batch_size + 1} of relationships.")
191+
logger.info(f"Imported batch {i // batch_size + 1} of relationships.")
174192
except Exception as e:
175-
logger.error(f"Error importing batch {i//batch_size + 1} of relationships: {e}")
193+
logger.error(f"Error importing batch {i // batch_size + 1} of relationships: {e}")
176194

177195

178196
# Main function to perform the import
@@ -198,25 +216,25 @@ def main():
198216
if relationship_df is not None:
199217
# Standardize relationship types
200218
relationship_df = standardize_relationship_types(relationship_df)
201-
219+
202220
# Infer node types if not present
203221
if 'start_node_type' not in relationship_df.columns or 'end_node_type' not in relationship_df.columns:
204222
logger.info("Inferring 'start_node_type' and 'end_node_type' based on node IDs...")
205223
relationship_df = infer_node_types(relationship_df, id_to_type)
206224

207225
# Check for unknown node types
208226
unknown_rels = relationship_df[
209-
(relationship_df['start_node_type'] == 'Unknown') |
227+
(relationship_df['start_node_type'] == 'Unknown') |
210228
(relationship_df['end_node_type'] == 'Unknown')
211-
]
229+
]
212230
if not unknown_rels.empty:
213231
logger.error("Some relationships have unknown node types. Please verify your data.")
214232
logger.error(unknown_rels)
215233
# Skip unknown relationships
216234
relationship_df = relationship_df[
217-
(relationship_df['start_node_type'] != 'Unknown') &
235+
(relationship_df['start_node_type'] != 'Unknown') &
218236
(relationship_df['end_node_type'] != 'Unknown')
219-
]
237+
]
220238

221239
# Import relationships
222240
with driver.session() as session:
@@ -229,5 +247,6 @@ def main():
229247
driver.close()
230248
logger.info("Neo4j import completed.")
231249

250+
232251
if __name__ == "__main__":
233252
main()

fe_repo/vite.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default defineConfig(({command}) => {
1414
},
1515
plugins: [react()],
1616
define: {
17-
__CURRENT_URI__: JSON.stringify(command == 'serve' ? 'http://34.23.225.150' : 'http://localhost')
17+
__CURRENT_URI__: JSON.stringify(command == 'serve' ? 'http://34.75.46.217' : 'http://localhost')
1818
}
1919
};
2020
})

0 commit comments

Comments
 (0)