File size: 5,545 Bytes
8e7f687
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# prompts_v1.py
# Improved prompts with minimal changes - adapted for current project

import re

# Router schema (same as current project)
ROUTER_SCHEMA = {
    "type": "object",
    "additionalProperties": False,
    "properties": {
        "intent": {
            "type": "string",
            "enum": ["career", "personal", "contact_exchange", "other"]
        },
        "why_hire": {"type": "boolean"},
        "requires_contact": {"type": "boolean"},
        "confidence": {
            "type": "number",
            "minimum": 0.0,
            "maximum": 1.0
        },
        "matched_phrases": {
            "type": "array",
            "items": {"type": "string"},
            "default": []
        }
    },
    "required": ["intent", "why_hire", "requires_contact", "confidence", "matched_phrases"]
}

# Keep current WHY_HIRE_REGEX (same as original)
WHY_HIRE_REGEX = re.compile(
    r"""(?xi)
    (?:why\s+(?:should|would|could|can|do)\s*(?:we\s+)?hire\s+you) |
    (?:why\s+hire\s+you) |
    (?:why\s+are\s+you\s+(?:a|the)\s+(?:good\s+)?fit) |
    (?:what\s+makes\s+you\s+(?:a|the)\s+(?:good\s+)?fit) |
    (?:why\s+you\s+for\s+(?:this|the)\s+role) |
    (?:why\s+are\s+you\s+right\s+for\s+(?:this|the)\s+job) |
    (?:what\s+value\s+will\s+you\s+bring) |
    (?:give\s+me\s+your\s+(?:pitch|elevator\s+pitch)) |
    (?:sell\s+yourself)
    """
)

# IMPROVEMENT: Pitch with short/long variants
def canonical_why_hire_pitch(short: bool = False) -> str:
    """
    Returns a concise or detailed pitch.
    - short=True: 2-3 sentences for quick replies.
    - short=False: fuller version with bullets.
    """
    if short:
        return (
            "I ship reliable, production-grade software quickly and back it with measurable impact. "
            "Recently I cut API latency by 81% for an AI SaaS and launched a Next.js 15 IDE on Vercel. "
            "I own delivery end-to-end, communicate clearly, and use AI where it genuinely moves the needle."
        )

    return (
        "I deliver reliable, production-grade software at high velocity and focus on measurable outcomes.\n\n"
        "β€’ AI & Product Engineering β€” Built CodeCraft, a real-time online IDE (Next.js 15, TypeScript, Convex, Clerk) "
        "deployed on Vercel; engineered an agentic career chatbot with tool calling and safe notification workflows.\n"
        "β€’ Proven Impact β€” Cut API latency by 81% for an AI SaaS; shipped a React SPA that lifted mobile bookings by 60% "
        "and reduced bounce rate by 25%.\n"
        "β€’ End-to-End Ownership β€” Move from Figma to production in months, manage multiple services, and maintain "
        "zero-downtime CI/CD pipelines.\n\n"
        "I work in tight feedback loops, keep quality high without slowing delivery, and add value from week one."
    )

# IMPROVEMENT: Structured router prompt with clear taxonomy
ROUTER_SYSTEM_PROMPT = """
You are a message router. Read the user's message and return ONLY a single JSON object.

### Output schema
{
  "intent": "career" | "personal" | "contact_exchange" | "other",
  "why_hire": boolean,
  "requires_contact": boolean,
  "confidence": number,
  "matched_phrases": string[]
}

### Intent taxonomy
{
  "career": [
    "resumes / CVs",
    "skills, projects, tech stack", 
    "job roles and titles",
    "work or education background",
    "intro prompts ('introduce yourself', 'tell me about yourself')",
    "portfolio requests"
  ],
  "personal": [
    "hobbies, sports, travel, lifestyle",
    "family or personal background",
    "non-career interests"
  ],
  "contact_exchange": [
    "providing or requesting email, phone, LinkedIn",
    "phrases like 'email me', 'my email is', 'how can I contact you'"
  ],
  "other": [
    "spam, harassment, off-topic, nonsense"
  ]
}

### Flags
- why_hire = true if user asks for pitch ('why hire you', 'what makes you a good fit', 'sell yourself')
- requires_contact = true if hiring/collaboration interest ('let's talk', portfolio requests, salary, availability) BUT false for pitch requests (why_hire=true)
- requires_contact = false if they only share contact details with no intent to engage

### Precedence
1. If contact info is provided or requested β†’ intent=contact_exchange
2. Otherwise choose between career vs personal (treat 'background' as career if work/education)
3. Otherwise β†’ other

Return short, lowercase triggers in matched_phrases. Language-agnostic. Return ONLY JSON.
""".strip()

# Keep current contact collection prompt (same as original)
CONTACT_COLLECTION_PROMPT = (
    "I'd be happy to discuss that personally. Could you share your email so I can connect with you? "
    "You can just say something like 'My email is [your-email]' and I'll make sure to reach out."
)

# Keep current system prompt builder (same as original)  
def build_system_prompt(name: str, domain_text: str, mode: str) -> str:
    """Build system prompt for the chatbot"""
    scope = "career" if mode == "career" else "personal"
    return f"""You are acting as {name}.
Answer only using {scope} information below. Do not invent personal facts outside these documents.

Strict tool policy:
- Use record_resume_gap ONLY for career questions you cannot answer from these documents.
- Do NOT record or notify for off-topic, harassing, sexual, discriminatory, or spam content.
- If the user provides contact details or asks to follow up, ask for an email and call record_user_details.

Be concise and professional. Gently redirect to career topics when appropriate.

## Documents
{domain_text}
"""