forked from stepanogil/autonomous-hr-chatbot
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtools.py
More file actions
198 lines (172 loc) · 7.03 KB
/
Copy pathtools.py
File metadata and controls
198 lines (172 loc) · 7.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
"""
HR tool implementations for the Responses API agent.
Defines three typed function tools that the model can call to answer
HR-related queries, together with the JSON schemas (``TOOL_SCHEMAS``) and
dispatch table (``TOOL_DISPATCH``) consumed by ``agent.py``.
The employee DataFrame is loaded once at module import time from the CSV path
resolved via the ``EMPLOYEE_CSV_PATH`` environment variable (defaults to
``employee_data.csv`` in the same directory as this file). Streamlit caches imported
modules per worker process, so the CSV is not re-read on every user message.
Tools
-----
get_employee_record(name)
Full employee record lookup by name.
list_direct_reports(supervisor_name)
Org-chart query returning all direct reports of a given supervisor.
compute_leave_encashment_value(name, days_to_encash)
Peso value calculation using the HR policy formula:
``basic_pay_in_php / 30 * days_to_encash``.
"""
import json
import os
import pandas as pd
from pathlib import Path
_csv_path = os.getenv("EMPLOYEE_CSV_PATH", str(Path(__file__).parent / "employee_data.csv"))
_df = pd.read_csv(_csv_path)
def get_employee_record(name: str) -> dict:
"""Return the full HR record for an employee by name (case-insensitive).
Args:
name: Full name of the employee, e.g. ``"Alexander Verdad"``.
Returns:
A dict with all CSV columns as keys — ``employee_id``, ``name``,
``position``, ``organizational_unit``, ``rank``, ``hire_date``,
``regularization_date``, ``vacation_leave``, ``sick_leave``,
``basic_pay_in_php``, ``employment_status``, ``supervisor`` — or
``{"error": "..."}`` if no matching employee is found.
"""
row = _df[_df["name"].str.lower() == name.lower()]
if row.empty:
return {"error": f"No employee found with name '{name}'"}
return row.iloc[0].to_dict()
def list_direct_reports(supervisor_name: str) -> list:
"""Return all employees whose supervisor column matches the given name.
Args:
supervisor_name: Full name of the supervisor, e.g. ``"Joseph Santos"``.
Returns:
A list of dicts, each containing ``name``, ``position``, and ``rank``
for one direct report. Returns an empty list if no reports are found.
"""
reports = _df[_df["supervisor"].str.lower() == supervisor_name.lower()]
if reports.empty:
return []
return reports[["name", "position", "rank"]].to_dict(orient="records")
def compute_leave_encashment_value(name: str, days_to_encash: int) -> dict:
"""Calculate the peso value of encashing unused leave days for an employee.
Applies the HR policy formula: ``basic_pay_in_php / 30 * days_to_encash``.
This matches the encashment rate defined in the HR policy for both Vacation
Leave and Service Incentive Leave (Sick Leave cannot be encashed per policy).
Args:
name: Full name of the employee.
days_to_encash: Number of unused leave days to convert to cash.
Returns:
A dict with keys ``basic_pay_in_php`` (float), ``days_to_encash``
(int), and ``encashment_value_php`` (float, rounded to 2 decimal
places), or ``{"error": "..."}`` if the employee is not found.
"""
row = _df[_df["name"].str.lower() == name.lower()]
if row.empty:
return {"error": f"No employee found with name '{name}'"}
basic_pay = float(row.iloc[0]["basic_pay_in_php"])
# policy formula: basic_pay / 30 * days_to_encash
value = basic_pay / 30 * days_to_encash
return {
"basic_pay_in_php": basic_pay,
"days_to_encash": days_to_encash,
"encashment_value_php": round(value, 2),
}
TOOL_SCHEMAS = [
{
"type": "function",
"name": "get_employee_record",
"description": (
"Look up a single employee's full record from the HR database. "
"Returns position, rank, leave balances (vacation_leave, sick_leave), "
"basic_pay_in_php, employment_status, supervisor, and hire dates."
),
"parameters": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Full name of the employee, e.g. 'Alexander Verdad'",
}
},
"required": ["name"],
"additionalProperties": False,
},
"strict": True,
},
{
"type": "function",
"name": "list_direct_reports",
"description": (
"Return a list of employees who report directly to the given supervisor. "
"Each entry includes name, position, and rank."
),
"parameters": {
"type": "object",
"properties": {
"supervisor_name": {
"type": "string",
"description": "Full name of the supervisor, e.g. 'Joseph Santos'",
}
},
"required": ["supervisor_name"],
"additionalProperties": False,
},
"strict": True,
},
{
"type": "function",
"name": "compute_leave_encashment_value",
"description": (
"Calculate the peso value of encashing unused leave days for an employee. "
"Uses the HR policy formula: basic_pay_in_php / 30 * days_to_encash."
),
"parameters": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Full name of the employee",
},
"days_to_encash": {
"type": "integer",
"description": "Number of leave days to encash",
},
},
"required": ["name", "days_to_encash"],
"additionalProperties": False,
},
"strict": True,
},
]
TOOL_DISPATCH = {
"get_employee_record": get_employee_record,
"list_direct_reports": list_direct_reports,
"compute_leave_encashment_value": compute_leave_encashment_value,
}
def dispatch(name: str, arguments_json: str) -> str:
"""Look up and call a tool by name, returning its result as a JSON string.
Used by the agent loop to execute function calls emitted by the model.
Errors from unknown tool names or bad arguments are caught and returned as
``{"error": "..."}`` JSON so the model can handle them gracefully rather
than crashing the agent loop.
Args:
name: The function name as declared in ``TOOL_SCHEMAS`` and
``TOOL_DISPATCH``.
arguments_json: JSON-encoded keyword arguments produced by the model,
e.g. ``'{"name": "Alexander Verdad"}'``.
Returns:
JSON-encoded result string ready to be sent back as a
``function_call_output`` input item.
"""
fn = TOOL_DISPATCH.get(name)
if fn is None:
return json.dumps({"error": f"Unknown tool: {name}"})
try:
args = json.loads(arguments_json)
result = fn(**args)
return json.dumps(result, default=str)
except Exception as exc:
return json.dumps({"error": str(exc)})