| from dotenv import load_dotenv |
| from openai import OpenAI |
| import json |
| import os |
| import requests |
| from pypdf import PdfReader |
| import gradio as gr |
|
|
|
|
| load_dotenv(override=True) |
|
|
| def push(text): |
| requests.post( |
| "https://api.pushover.net/1/messages.json", |
| data={ |
| "token": os.getenv("PUSHOVER_TOKEN"), |
| "user": os.getenv("PUSHOVER_USER"), |
| "message": text, |
| } |
| ) |
|
|
|
|
| def record_user_details(email="Email not provided", name="Name not provided", notes="not provided"): |
| push(f"Recording {name} with email {email} and notes {notes}") |
| return {"recorded": "ok"} |
|
|
| def record_unknown_question(question): |
| push(f"Recording {question}") |
| return {"recorded": "ok"} |
|
|
| record_user_details_json = { |
| "name": "record_user_details", |
| "description": "Use this tool to record that a user is interested in being in touch and provided an email address", |
| "parameters": { |
| "type": "object", |
| "properties": { |
| "email": { |
| "type": "string", |
| "description": "The email address of this user" |
| }, |
| "name": { |
| "type": "string", |
| "description": "The user's name, if they provided it" |
| } |
| , |
| "notes": { |
| "type": "string", |
| "description": "Any additional information about the conversation that's worth recording to give context" |
| } |
| }, |
| "required": ["email"], |
| "additionalProperties": False |
| } |
| } |
|
|
| record_unknown_question_json = { |
| "name": "record_unknown_question", |
| "description": "Always use this tool to record any question that couldn't be answered as you didn't know the answer", |
| "parameters": { |
| "type": "object", |
| "properties": { |
| "question": { |
| "type": "string", |
| "description": "The question that couldn't be answered" |
| }, |
| }, |
| "required": ["question"], |
| "additionalProperties": False |
| } |
| } |
|
|
| tools = [{"type": "function", "function": record_user_details_json}, |
| {"type": "function", "function": record_unknown_question_json}] |
|
|
|
|
| class Me: |
|
|
| def __init__(self): |
| GEMINI_BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai/" |
| self.openai = OpenAI(base_url=GEMINI_BASE_URL,api_key=os.getenv("GEMINI_API_KEY")) |
| self.name = "Gowtham Siddartha" |
| reader = PdfReader("me/Gowtham-Siddartha-P-Resume-.pdf") |
| self.linkedin = "" |
| for page in reader.pages: |
| text = page.extract_text() |
| if text: |
| self.linkedin += text |
| with open("me/summary.txt", "r", encoding="utf-8") as f: |
| self.summary = f.read() |
|
|
|
|
| def handle_tool_call(self, tool_calls): |
| results = [] |
| for tool_call in tool_calls: |
| tool_name = tool_call.function.name |
| arguments = json.loads(tool_call.function.arguments) |
| print(f"Tool called: {tool_name}", flush=True) |
| tool = globals().get(tool_name) |
| result = tool(**arguments) if tool else {} |
| results.append({"role": "tool","content": json.dumps(result),"tool_call_id": tool_call.id}) |
| return results |
| |
| def system_prompt(self): |
| system_prompt = """You are acting as {self.name}. You are answering questions on {self.name}'s website. |
| |
| -> Start every interaction by greeting the visitor warmly and introducing yourself as {self.name}. |
| -> Then, politely ask for their name before answering any questions. |
| |
| - If the visitor provides their name (or any other personal details such as email), immediately record them using the `record_user_details` tool. |
| - If the visitor does not provide a name or details, do not record anything and do not send any notification — just continue the conversation normally. |
| |
| Once the name step is complete (or if the user refuses), begin answering their questions. |
| Use a friendly and humble tone, include emojis where appropriate, and keep your responses professional and engaging. |
| |
| Focus particularly on questions related to {self.name}'s career, background, skills, and experience. You have access to a summary of {self.name}'s background and LinkedIn profile — use this to answer faithfully. |
| |
| If you do not know the answer to a question, use the `record_unknown_question` tool to log it (even if the question is trivial or unrelated). |
| |
| If the conversation continues, try to guide the visitor toward sharing more details (such as their email) so you can stay in touch. If they provide these details, record them with the `record_user_details` tool. |
| |
| Your responsibility is to represent {self.name} authentically, as if talking to a potential client or future employer visiting the website. |
| """ |
| system_prompt += f"\n\n## Summary:\n{self.summary}\n\n## LinkedIn Profile:\n{self.linkedin}\n\n" |
| system_prompt += f"With this context, please chat with the user, always staying in character as {self.name}." |
| return system_prompt |
| |
| def chat(self, message, history): |
| messages = [{"role": "system", "content": self.system_prompt()}] + history + [{"role": "user", "content": message}] |
| done = False |
| while not done: |
| response = self.openai.chat.completions.create(model="gemini-2.0-flash", messages=messages, tools=tools) |
| if response.choices[0].finish_reason=="tool_calls": |
| message = response.choices[0].message |
| tool_calls = message.tool_calls |
| results = self.handle_tool_call(tool_calls) |
| messages.append(message) |
| messages.extend(results) |
| else: |
| done = True |
| return response.choices[0].message.content |
| |
|
|
| if __name__ == "__main__": |
| me = Me() |
| gr.ChatInterface(me.chat, type="messages").launch() |
| |