Spaces:
Running
Running
import os | |
import json | |
from openai import OpenAI | |
from dotenv import load_dotenv | |
from tools import _record_user_details | |
load_dotenv(override=True) | |
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") | |
MODEL = "gpt-4o-mini-2024-07-18" | |
NAME = "Damla" | |
# Tool: Record user interest | |
record_user_details_json = { | |
"name": "record_user_details", | |
"description": "Use this tool to record that a user provided an email address and they are interested in being in touch and provided an email address", | |
"parameters": { | |
"type": "object", | |
"properties": { | |
"email": { | |
"type": "string", | |
"description": "The email address of this user. Format should be similar to this: placeholder@domain.com" | |
}, | |
"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 | |
} | |
} | |
TOOL_FUNCTIONS = { | |
"record_user_details": _record_user_details, | |
} | |
TOOLS = [{"type": "function", "function": record_user_details_json}] | |
class Chat: | |
def __init__(self, name=NAME, model=MODEL, tools=TOOLS): | |
self.name = name | |
self.model = model | |
self.tools = tools | |
self.client = OpenAI() | |
def _get_system_prompt(self): | |
return (f""" | |
You are acting as {self.name}. You are answering questions on {self.name}'s website, particularly questions related to {self.name}'s career, background, skills, and experience. | |
You are given a summary of {self.name}'s background and LinkedIn profile which you should use as the only source of truth to answer questions. | |
Interpret and answer based strictly on the information provided. | |
You should never generate or write code. If asked to write code or build an app, explain whether {self.name}'s experience or past projects are relevant to the task, | |
and what approach {self.name} would take. If {self.name} has no relevant experience, politely acknowledge that. | |
If a project is mentioned, specify whether it's a personal project or a professional one. Be professional and engaging — | |
the tone should be warm, clear, and appropriate for a potential client or future employer. | |
If a visitor engages in a discussion, try to steer them towards getting in touch via email. Ask for their email and record it using your record_user_details tool. | |
Only accept inputs that follow the standard email format (like name@example.com). Do not confuse emails with phone numbers or usernames. If in doubt, ask for clarification. | |
If you don't know the answer, just say so. | |
""" | |
) | |
def _handle_tool_calls(self, tool_calls, recorded_emails): | |
results = [] | |
for call in tool_calls: | |
tool_name = call.function.name | |
arguments = json.loads(call.function.arguments) | |
if arguments["email"] in recorded_emails: | |
result = {"recorded": "ok"} | |
results.append({ | |
"role": "tool", | |
"content": json.dumps(result), | |
"tool_call_id": call.id | |
}) | |
continue | |
print(f"Tool called: {tool_name}") | |
func = TOOL_FUNCTIONS.get(tool_name) | |
if func: | |
result = func(**arguments) | |
results.append({ | |
"role": "tool", | |
"content": json.dumps(result), | |
"tool_call_id": call.id | |
}) | |
recorded_emails.add(arguments["email"]) | |
return results | |
def chat(self, message, history, recorded_emails=set(), retrieved_chunks=None): | |
if retrieved_chunks: | |
message += f"\n\nUse the following context if helpful:\n{retrieved_chunks}" | |
messages = [{"role": "system", "content": self._get_system_prompt()}] + history + [{"role": "user", "content": message}] | |
done = False | |
while not done: | |
response = self.client.chat.completions.create( | |
model=self.model, | |
messages=messages, | |
tools=self.tools, | |
max_tokens=400, | |
temperature=0.5 | |
) | |
finish_reason = response.choices[0].finish_reason | |
if finish_reason == "tool_calls": | |
message_obj = response.choices[0].message | |
tool_calls = message_obj.tool_calls | |
results = self._handle_tool_calls(tool_calls, recorded_emails) | |
messages.append(message_obj) | |
messages.extend(results) | |
else: | |
done = True | |
return response.choices[0].message.content, recorded_emails | |
def rerun(self, original_reply, message, history, feedback): | |
updated_prompt = self._get_system_prompt() | |
updated_prompt += ( | |
"\n\n## Previous answer rejected\nYou just tried to reply, but the quality control rejected your reply.\n" | |
f"## Your attempted answer:\n{original_reply}\n\n" | |
f"## Reason for rejection:\n{feedback}\n" | |
) | |
messages = [{"role": "system", "content": updated_prompt}] + history + [{"role": "user", "content": message}] | |
response = self.client.chat.completions.create(model=self.model, messages=messages) | |
return response.choices[0].message.content | |