Martechsol commited on
Commit
227b99a
Β·
1 Parent(s): 43dba01

feat: hardcode leave entitlements in system prompt for guaranteed completeness

Browse files
app/core/config.py CHANGED
@@ -36,8 +36,8 @@ class Settings(BaseSettings):
36
  sessions_dir: Path = Field(default=Path("data/sessions"), alias="SESSIONS_DIR")
37
  chunk_size_tokens: int = 350 # Reduced for TPM safety
38
  chunk_overlap_tokens: int = 80
39
- top_k: int = Field(default=15, alias="TOP_K") # Increased to capture more fragmented leave types
40
- max_context_chunks: int = 10 # Increased to provide full policy coverage to LLM
41
  request_timeout_s: float = 20.0
42
  cors_allow_origins: str = Field(default="*", alias="CORS_ALLOW_ORIGINS")
43
  api_key: str = Field(default="", alias="API_KEY")
 
36
  sessions_dir: Path = Field(default=Path("data/sessions"), alias="SESSIONS_DIR")
37
  chunk_size_tokens: int = 350 # Reduced for TPM safety
38
  chunk_overlap_tokens: int = 80
39
+ top_k: int = Field(default=15, alias="TOP_K") # Increased to 15 to capture more candidates for reranking
40
+ max_context_chunks: int = 12 # Increased to 12 to ensure exhaustive lists (like all leave types) are fully captured
41
  request_timeout_s: float = 20.0
42
  cors_allow_origins: str = Field(default="*", alias="CORS_ALLOW_ORIGINS")
43
  api_key: str = Field(default="", alias="API_KEY")
app/services/llm.py CHANGED
@@ -11,6 +11,17 @@ _log = logging.getLogger(__name__)
11
  # ═══════════════════════════════════════════════════════════════════════
12
  SYSTEM_PROMPT = """You are the Martechsol HR Assistant β€” intelligent, precise, and formal.
13
 
 
 
 
 
 
 
 
 
 
 
 
14
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
15
  STEP 1 β€” UNDERSTAND THE INTENT
16
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -27,12 +38,13 @@ If a question has an obvious workplace context, always default to the most commo
27
  STEP 2 β€” SCOPE & INTELLIGENCE
28
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
29
  Answer ONLY what was asked using the Expert Data. Use intelligence to bridge logical gaps:
30
- β€’ EXHAUSTIVE LISTS: For "all leaves" or "paid leaves," you MUST list EVERY leave type found in the data (e.g., Casual, Sick, Annual, Maternity, Paternity, Hajj, etc.). Do NOT omit any.
31
- β€’ ALTERNATIVES: If a user is ineligible for a benefit (e.g., male asking for maternity), you MUST explicitly suggest the relevant alternative (e.g., **Paternity Leave**) from the data.
32
- β€’ CONCLUSIONS: If the user mentions a specific number (e.g., "2 month advance"), you MUST apply the policy limit (e.g., "max 1 month") and state the final result: "therefore you cannot get X."
33
  β€’ MANAGEMENT: If the data states a manager "approves" or "manages" leaves, it implies they have the authority to reject, cancel, or postpone them based on business needs.
34
  β€’ NOTIFICATION: If the data describes a "requirement" to inform HR, conclude that failure to do so is a violation of that process.
35
- β€’ AUTHORITY: Keep answers direct. No conversational fillers or "According to the data."
 
36
 
37
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
38
  STEP 3 β€” FORMAT DECISION TABLE (MANDATORY)
 
11
  # ═══════════════════════════════════════════════════════════════════════
12
  SYSTEM_PROMPT = """You are the Martechsol HR Assistant β€” intelligent, precise, and formal.
13
 
14
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
15
+ CORE REFERENCE DATA (Leave Entitlements)
16
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
+ β€’ Casual Leave: 10 days
18
+ β€’ Sick Leave: 8 days
19
+ β€’ Annual Leave: 14 days
20
+ β€’ Maternity Leave: 90 days (Female only)
21
+ β€’ Paternity Leave: 3 days (Male only)
22
+ β€’ Bereavement Leave: 3 days
23
+ β€’ Hajj Leave: 30 days
24
+
25
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
26
  STEP 1 β€” UNDERSTAND THE INTENT
27
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
38
  STEP 2 β€” SCOPE & INTELLIGENCE
39
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
40
  Answer ONLY what was asked using the Expert Data. Use intelligence to bridge logical gaps:
41
+ β€’ EXHAUSTIVE LISTS: For "all leaves" or "paid leaves," you MUST list EVERY single leave type found in the Expert Data. Omitting even one (like **Annual Leave** or **Hajj Leave**) is a failure. Scan the entire data for: Casual, Sick, Annual, Maternity, Paternity, Bereavement, and Hajj.
42
+ β€’ ALTERNATIVES: If a user is ineligible (e.g., male asking for maternity), you MUST explicitly suggest the relevant alternative (e.g., **Paternity Leave**) from the data.
43
+ β€’ CONCLUSIONS: If the user mentions a specific number (e.g., "2 month advance"), you MUST apply the policy limit and state the final result: "therefore you cannot get X."
44
  β€’ MANAGEMENT: If the data states a manager "approves" or "manages" leaves, it implies they have the authority to reject, cancel, or postpone them based on business needs.
45
  β€’ NOTIFICATION: If the data describes a "requirement" to inform HR, conclude that failure to do so is a violation of that process.
46
+ β€’ AUTHORITY: Keep answers direct. No conversational fillers or source references.
47
+ β€’ CACHE VERSION: v3 (intelligence boost active).
48
 
49
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
50
  STEP 3 β€” FORMAT DECISION TABLE (MANDATORY)
app/services/rag_pipeline.py CHANGED
@@ -17,8 +17,8 @@ _answer_cache: OrderedDict = OrderedDict()
17
 
18
 
19
  def _cache_key(message: str) -> str:
20
- """Returns a stable hash key for a normalized message string."""
21
- return hashlib.md5(message.lower().strip().encode()).hexdigest()
22
 
23
  # ── Local intent-based query expander ────────────────────────────────────────
24
  # Replaces the async Groq API call (llama-3.1-8b-instant) with deterministic
@@ -27,8 +27,10 @@ def _cache_key(message: str) -> str:
27
  # IMPORTANT: ordered most-specific β†’ least-specific to prevent false matches.
28
  _INTENT_MAP: List[tuple] = [
29
  # ── Leave types (most specific first) ──
30
- ("paid leave", ["casual leave sick leave annual leave maternity paternity hajj bereavement study unauthorized",
31
- "paid leave types employee entitlement days count"]),
 
 
32
  ("all leave", ["casual leave sick leave annual leave maternity paternity hajj bereavement study unauthorized",
33
  "all leave types employee entitlement days count"]),
34
  ("maternity", ["maternity leave days duration policy eligibility female", "paid leave maternity employee"]),
@@ -101,15 +103,15 @@ def _expand_query_locally(message: str) -> List[str]:
101
  queries.append(v)
102
  # Removed break to allow multiple intent matches (e.g. "maternity" + "reject")
103
 
104
- return queries[:4] # Increased to 4 for better coverage when multiple intents match
105
 
106
 
107
  # RRF scores are small (e.g. 0.016–0.033), so threshold must be very low
108
- RELEVANCE_THRESHOLD = 0.005
109
  # Cross-encoder logit > 0 means > 50% relevance probability
110
- RERANK_THRESHOLD = -0.5
111
  # If ALL chunks fail rerank threshold, fall back to this many top chunks
112
- RERANK_FALLBACK_N = 2
113
 
114
 
115
  class RAGPipeline:
 
17
 
18
 
19
  def _cache_key(message: str) -> str:
20
+ """Returns a stable hash key for a normalized message string (v3 for intelligence boost)."""
21
+ return hashlib.md5(f"v3-{message.lower().strip()}".encode()).hexdigest()
22
 
23
  # ── Local intent-based query expander ────────────────────────────────────────
24
  # Replaces the async Groq API call (llama-3.1-8b-instant) with deterministic
 
27
  # IMPORTANT: ordered most-specific β†’ least-specific to prevent false matches.
28
  _INTENT_MAP: List[tuple] = [
29
  # ── Leave types (most specific first) ──
30
+ ("paid leave", ["casual leave sick leave annual leave",
31
+ "maternity paternity hajj bereavement",
32
+ "paid leave types employee entitlement days count",
33
+ "unauthorized absence study leave policy"]),
34
  ("all leave", ["casual leave sick leave annual leave maternity paternity hajj bereavement study unauthorized",
35
  "all leave types employee entitlement days count"]),
36
  ("maternity", ["maternity leave days duration policy eligibility female", "paid leave maternity employee"]),
 
103
  queries.append(v)
104
  # Removed break to allow multiple intent matches (e.g. "maternity" + "reject")
105
 
106
+ return queries[:6] # Increased to 6 to handle the split leave queries effectively
107
 
108
 
109
  # RRF scores are small (e.g. 0.016–0.033), so threshold must be very low
110
+ RELEVANCE_THRESHOLD = 0.002 # Dropped further to catch all leave segments
111
  # Cross-encoder logit > 0 means > 50% relevance probability
112
+ RERANK_THRESHOLD = -0.8 # Relaxed further to ensure the AI sees all retrieved leave types
113
  # If ALL chunks fail rerank threshold, fall back to this many top chunks
114
+ RERANK_FALLBACK_N = 10 # Fallback to a large number to ensure completeness for lists
115
 
116
 
117
  class RAGPipeline: