Skip to content

Commit 1677e05

Browse files
authored
Merge pull request #51 from PentabyteDevAlign/feat/profile-menu
Feat/profile menu
2 parents 2c9ea81 + 4540a16 commit 1677e05

11 files changed

Lines changed: 774 additions & 296 deletions

File tree

AI/src/agents/recommendation_agent/model.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
class CandidateModel(BaseModel):
77
"""Model to represent a candidate with relevant metrics."""
8+
_id: str
89
name: str
910
position: str
1011
skills: List[str]

AI/src/api/roster.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ def cosine_similarity(vec_a, vec_b):
289289

290290
# 5. Merge all the data
291291
result = {
292+
"_id": str(user_id),
292293
"name": user.get("name"),
293294
"position": position_name,
294295
"skills": [skill["name"] for skill in skills],
@@ -313,6 +314,7 @@ def cosine_similarity(vec_a, vec_b):
313314
# group by position
314315
grouped = defaultdict(list)
315316
for s in scores:
317+
print(s)
316318
grouped[s["position"]].append(s)
317319

318320
required_map = {p.name: p.numOfRequest for p in required_positions}
@@ -339,6 +341,7 @@ def cosine_similarity(vec_a, vec_b):
339341
project_description=project_description,
340342
candidates=candidates
341343
)
344+
print(response)
342345

343346
indexes = response.ordered_indexes
344347
reasoning = response.reasoning
@@ -354,9 +357,13 @@ def cosine_similarity(vec_a, vec_b):
354357

355358
# Terapkan urutan ke kandidat
356359
ordered = [top_candidates[position][i] for i in indexes]
360+
print("odde")
361+
print(ordered)
357362

358363
# Tambahkan rank number
359364
for idx, c in enumerate(ordered, start=1):
365+
print("caca")
366+
print(c)
360367
c["rank"] = idx
361368
c["reason"] = reasoning
362369

@@ -365,5 +372,6 @@ def cosine_similarity(vec_a, vec_b):
365372

366373
logs["total_execution_time"] = time.time() - total_start_time
367374
print(logs)
368-
375+
print("ptada")
376+
print(top_candidates)
369377
return {"success": True, "data": top_candidates}

AI/src/models/roster.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
from pydantic import BaseModel
1+
from pydantic import BaseModel, field_validator
22
from typing import List, Dict
3+
from bson import ObjectId
34

45
class ProjectEmbeddingsResponse(BaseModel):
56
status: str
67
project_id: str
78

89
class Candidate(BaseModel):
10+
_id: str
911
name: str
1012
position: str
1113
skills: List[str]
@@ -16,6 +18,12 @@ class Candidate(BaseModel):
1618
rank: int
1719
reason: str
1820

21+
@field_validator('_id', mode='before')
22+
def convert_objectId(cls, v):
23+
if isinstance(v, ObjectId):
24+
return str(v)
25+
return v
26+
1927
class RosterRecommendationsResponse(BaseModel):
2028
success: bool
2129
data: Dict[str, List[Candidate]]

Backend/controllers/hr.controller.js

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ const listEmployees = async (req, res) => {
201201
if (userIds.length > 0) {
202202
const counts = await ProjectAssignment.aggregate([
203203
{ $match: { userId: { $in: userIds } } },
204-
{ $group: { _id: '$userId', count: { $sum: 1 } } },
204+
{ $group: { _id: "$userId", count: { $sum: 1 } } },
205205
]).exec();
206206
counts.forEach((c) => projectCountsMap.set(String(c._id), c.count));
207207
}
@@ -263,7 +263,9 @@ const getEmployee = async (req, res) => {
263263
const response = userDto.mapUserToUserResponse(user);
264264
// attach project count for this employee
265265
try {
266-
const projCount = await ProjectAssignment.countDocuments({ userId: user._id });
266+
const projCount = await ProjectAssignment.countDocuments({
267+
userId: user._id,
268+
});
267269
response.projectCount = projCount;
268270
} catch (e) {
269271
// non-fatal: if counting fails, default to 0
@@ -802,32 +804,33 @@ const parseCv = async (req, res) => {
802804
const getColleagues = async (req, res) => {
803805
try {
804806
const currentUserId = req.user.id || req.user._id;
805-
const currentUser = await User.findById(currentUserId).select('role managerId').lean();
807+
const currentUser = await User.findById(currentUserId)
808+
.select("role managerId")
809+
.lean();
806810

807811
if (!currentUser) {
808812
return res.status(404).json({
809813
success: false,
810814
error: "Not Found",
811-
message: "Current user not found"
815+
message: "Current user not found",
812816
});
813817
}
814818

815819
let colleagues = [];
816820
let directManager = null;
817821

818-
if (currentUser.role === 'manager') {
822+
if (currentUser.role === "manager") {
819823
// If user is manager, get all direct subordinates (members with managerId = currentUser._id)
820824
colleagues = await User.find({
821825
managerId: currentUserId,
822826
active: true,
823-
_id: { $ne: currentUserId } // Exclude self
827+
_id: { $ne: currentUserId }, // Exclude self
824828
})
825829
.populate("position", "name")
826830
.populate("skills", "name")
827831
.select("_id name email role position skills")
828832
.sort({ name: 1 })
829833
.lean();
830-
831834
} else {
832835
// If user is staff or HR, get teammates (colleagues with same manager) and include direct manager
833836
if (currentUser.managerId) {
@@ -841,7 +844,7 @@ const getColleagues = async (req, res) => {
841844
const teammates = await User.find({
842845
managerId: currentUser.managerId,
843846
active: true,
844-
_id: { $ne: currentUserId } // Exclude self
847+
_id: { $ne: currentUserId }, // Exclude self
845848
})
846849
.populate("position", "name")
847850
.populate("skills", "name")
@@ -854,28 +857,32 @@ const getColleagues = async (req, res) => {
854857
}
855858

856859
// Format response
857-
const formattedColleagues = colleagues.map(colleague => ({
860+
const formattedColleagues = colleagues.map((colleague) => ({
858861
id: colleague._id,
859862
name: colleague.name,
860863
email: colleague.email,
861864
role: colleague.role,
862-
position: colleague.position ? {
863-
id: colleague.position._id,
864-
name: colleague.position.name
865-
} : null,
866-
skills: colleague.skills ? colleague.skills.map(skill => ({
867-
id: skill._id,
868-
name: skill.name
869-
})) : []
865+
position: colleague.position
866+
? {
867+
id: colleague.position._id,
868+
name: colleague.position.name,
869+
}
870+
: null,
871+
skills: colleague.skills
872+
? colleague.skills.map((skill) => ({
873+
id: skill._id,
874+
name: skill.name,
875+
}))
876+
: [],
870877
}));
871878

872879
const response = {
873880
success: true,
874881
data: {
875882
userRole: currentUser.role,
876883
colleagues: formattedColleagues,
877-
totalColleagues: formattedColleagues.length
878-
}
884+
totalColleagues: formattedColleagues.length,
885+
},
879886
};
880887

881888
// Include manager info if it exists
@@ -885,10 +892,12 @@ const getColleagues = async (req, res) => {
885892
name: directManager.name,
886893
email: directManager.email,
887894
role: directManager.role,
888-
position: directManager.position ? {
889-
id: directManager.position._id,
890-
name: directManager.position.name
891-
} : null
895+
position: directManager.position
896+
? {
897+
id: directManager.position._id,
898+
name: directManager.position.name,
899+
}
900+
: null,
892901
};
893902
}
894903

@@ -897,7 +906,7 @@ const getColleagues = async (req, res) => {
897906
return res.status(500).json({
898907
success: false,
899908
error: "Internal Server Error",
900-
message: err.message
909+
message: err.message,
901910
});
902911
}
903912
};

0 commit comments

Comments
 (0)