File size: 6,817 Bytes
02acac5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import os
import sys
import json
import google.generativeai as genai

from intent_detector import detect_intent
from rag_utils import retrieve_profiles, retrieve_jobs

# 1. Configure Gemini
API_KEY = os.getenv("GOOGLE_API_KEY")
if not API_KEY:
    raise ValueError("Error: Set GOOGLE_API_KEY environment variable before running.")
genai.configure(api_key=API_KEY)  #type:ignore

# 2. System prompt with few-shot examples for each mode: ONBOARD, SEARCH, POST
SYSTEM_PROMPT = """

You are a single AI assistant that can perform any of the following three tasks based on the user's request:



1. ONBOARD – Onboard a work professional by capturing their profile details such as name, role, skills, experience, and location. If information is missing, ask for it. If user already exists (by matching query to stored profiles), tell them they are already onboarded.



2. SEARCH – Search for job opportunities. Given a user's query (e.g., "Remote React developer paying at least $60k"), retrieve relevant job listings and present them in a concise format (title, company, type, salary).



3. POST – Create a structured job opportunity (for clients). Given a client's unstructured description (e.g., "I need someone to build a website for $2000 in 3 weeks"), produce a JSON‐style job post with fields: title, description, skills, budget, timeline.



Respond according to these rules:

- First, identify which of the three tasks the user is requesting (ONBOARD, SEARCH, or POST).

- Then, perform that task. If any details are missing from the user's request, ask a clarifying question.

- Always keep answers concise (2–4 sentences) and in plain English, except for the POST task, where you output a valid JSON object without extra markdown.



Below are three examples (few‐shot) to demonstrate expected behavior:



---



Example 1 – ONBOARD:

User: "I'm a backend developer with 4 years of experience in Python and Django, based in New York."

Assistant: "ONBOARD



Sure! Let me gather your onboarding details:

• Name: [please tell me your full name]

• Role: Backend Developer

• Skills: Python, Django

• Experience: 4 years

• Location: New York

Please confirm your full name so I can complete your profile."



---



Example 2 – SEARCH:

User: "Show me remote React jobs paying at least $50k/year."

Assistant: "SEARCH



Here are three remote React developer roles paying ≥ $50k/year:

1) Senior React Developer at AcmeCorp (Remote, USD 70k–90k)

2) Frontend Engineer at BetaTech (Remote, USD 55k–65k)

3) Fullstack Engineer at GammaWorks (Hybrid, USD 60k–80k)

Let me know if you want more details or a narrower focus."



---



Example 3 – POST:

User: "I need a WordPress expert to build a blog site, budget is around $1000."

Assistant: "POST



{

  \"title\": \"WordPress Developer for Blog Site\",

  \"description\": \"Create a blog site with a custom theme, SEO optimization, and social sharing features.\",

  \"skills\": [\"WordPress\", \"PHP\", \"HTML\", \"CSS\"],

  \"budget\": \"$1000\",

  \"timeline\": \"3 weeks\"

}"



---



Now, when a new user message arrives, first identify the intent (ONBOARD, SEARCH, or POST), and then follow the instructions above to respond properly.

"""

def chat_loop(model_name="gemini-1.5-flash"):
    """

    Main chat loop that handles conversation with context injection based on intent.

    """
    print(f"=== Multi-Task Gemini Chatbot (Model: {model_name}) ===")
    print("Type your message below. Type 'exit' to quit.\n")

    # Initialize the model
    model = genai.GenerativeModel(model_name) #type:ignore
    
    # Start a chat session with the system prompt
    chat = model.start_chat(history=[])

    while True:
        try:
            user_input = input("You: ").strip()
        except (KeyboardInterrupt, EOFError):
            print("\nExiting. Goodbye!")
            break

        if not user_input:
            continue
        if user_input.lower() == "exit":
            print("Goodbye!")
            break

        try:
            # 1. Detect intent (ONBOARD / SEARCH / POST)
            intent = detect_intent(user_input, model=model_name)
            print(f"[Debug] Detected intent: {intent}")

            # 2. Depending on intent, retrieve context
            context_block = None
            if intent == "SEARCH":
                # Use RAG to get top-3 job listings
                job_results = retrieve_jobs(user_input, top_k=3)
                # Format as a plain text block
                lines = []
                for idx, job in enumerate(job_results, start=1):
                    lines.append(f"{idx}) {job['text']}")
                block_text = "\n".join(lines)
                context_block = f"Relevant job listings:\n{block_text}"
            elif intent == "ONBOARD":
                # Use RAG to find if a similar profile already exists
                profile_results = retrieve_profiles(user_input, top_k=3)
                lines = []
                for idx, prof in enumerate(profile_results, start=1):
                    lines.append(f"{idx}) {prof['text']}")
                block_text = "\n".join(lines)
                context_block = f"Existing profiles that match your query:\n{block_text}"
            # else: if intent == "POST", we do not need RAG because POST is rule‐based

            # 3. Prepare the full prompt
            full_prompt = SYSTEM_PROMPT
            if context_block:
                full_prompt += f"\n\nContext Information:\n{context_block}"
                print(f"[Debug] Injected context block:\n{context_block}\n")
            
            full_prompt += f"\n\nUser: {user_input}\nAssistant:"

            # 4. Generate response
            response = model.generate_content(full_prompt)
            assistant_reply = response.text

            # 5. Print assistant's reply
            print(f"\nBot: {assistant_reply}\n")

        except Exception as e:
            print(f"[Error] Gemini API call failed: {e}")
            print("Please try again or check your API key and internet connection.\n")
            continue

def main():
    """Main function to start the chatbot."""
    chosen_model = sys.argv[1] if len(sys.argv) > 1 else "gemini-1.5-flash"
    
    # Validate model name
    available_models = ["gemini-1.5-flash", "gemini-1.5-pro", "gemini-pro"]
    if chosen_model not in available_models:
        print(f"Warning: Model '{chosen_model}' may not be available.")
        print(f"Available models: {', '.join(available_models)}")
        print(f"Using default: gemini-1.5-flash\n")
        chosen_model = "gemini-1.5-flash"
    
    chat_loop(model_name=chosen_model)

if __name__ == "__main__":
    main()