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 | |