jisaacso219 commited on
Commit
ff0e3f2
·
verified ·
1 Parent(s): a253231

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +94 -74
app.py CHANGED
@@ -6,18 +6,23 @@ import requests
6
  from PyPDF2 import PdfReader
7
  import gradio as gr
8
  import gdown
 
 
9
 
10
  load_dotenv(override=True)
11
 
12
  def push(text):
13
- requests.post(
14
- "https://api.pushover.net/1/messages.json",
15
- data={
16
- "token": os.getenv("PUSHOVER_TOKEN"),
17
- "user": os.getenv("PUSHOVER_USER"),
18
- "message": text,
19
- }
20
- )
 
 
 
21
 
22
  def record_user_details(email, name="Name not provided", notes="not provided"):
23
  push(f"Recording {name} with email {email} and notes {notes}")
@@ -33,18 +38,9 @@ record_user_details_json = {
33
  "parameters": {
34
  "type": "object",
35
  "properties": {
36
- "email": {
37
- "type": "string",
38
- "description": "The email address of this user"
39
- },
40
- "name": {
41
- "type": "string",
42
- "description": "The user's name, if they provided it"
43
- },
44
- "notes": {
45
- "type": "string",
46
- "description": "Any additional information about the conversation that's worth recording to give context"
47
- }
48
  },
49
  "required": ["email"],
50
  "additionalProperties": False
@@ -53,88 +49,112 @@ record_user_details_json = {
53
 
54
  record_unknown_question_json = {
55
  "name": "record_unknown_question",
56
- "description": "Always use this tool to record any question that couldn't be answered as you didn't know the answer",
57
  "parameters": {
58
  "type": "object",
59
  "properties": {
60
- "question": {
61
- "type": "string",
62
- "description": "The question that couldn't be answered"
63
- },
64
  },
65
  "required": ["question"],
66
  "additionalProperties": False
67
  }
68
  }
69
 
70
- tools = [{"type": "function", "function": record_user_details_json},
71
- {"type": "function", "function": record_unknown_question_json}]
 
 
72
 
73
  class Me:
74
-
75
  def __init__(self):
76
  self.openai = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
77
  self.name = "Jacob Isaacson"
 
 
78
 
79
- # Download LinkedIn PDF using gdown
80
  linkedin_id = "1xz2RowkImpI8odYv8zvKdlRHaKfILn40"
81
- linkedin_path = "Linkedin.pdf"
82
- gdown.download(f"https://drive.google.com/uc?id={linkedin_id}", linkedin_path, quiet=False)
83
- reader = PdfReader(linkedin_path)
84
 
85
- self.linkedin = ""
86
- for page in reader.pages:
87
- text = page.extract_text()
88
- if text:
89
- self.linkedin += text
90
-
91
- # Download summary.txt using gdown
92
  summary_id = "1hjJz082YFSVjFtpO0pwT6Tyy3eLYYj6-"
93
- summary_path = "summary.txt"
94
- gdown.download(f"https://drive.google.com/uc?id={summary_id}", summary_path, quiet=False)
95
-
96
- with open(summary_path, "r", encoding="utf-8") as f:
97
  self.summary = f.read()
98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  def handle_tool_call(self, tool_calls):
100
  results = []
101
  for tool_call in tool_calls:
102
  tool_name = tool_call.function.name
103
  arguments = json.loads(tool_call.function.arguments)
104
- print(f"Tool called: {tool_name}", flush=True)
105
  tool = globals().get(tool_name)
106
  result = tool(**arguments) if tool else {}
107
- results.append({"role": "tool", "content": json.dumps(result), "tool_call_id": tool_call.id})
108
  return results
109
 
110
- def system_prompt(self):
111
- system_prompt = f"You are acting as {self.name}. You are answering questions on {self.name}'s website, \
112
- particularly questions related to {self.name}'s career, background, skills and experience. \
113
- Your responsibility is to represent {self.name} for interactions on the website as faithfully as possible. \
114
- You are given a summary of {self.name}'s background and LinkedIn profile which you can use to answer questions. \
115
- Be professional and engaging, as if talking to a potential client or future employer who came across the website. \
116
- If you don't know the answer to any question, use your record_unknown_question tool to record the question that you couldn't answer, even if it's about something trivial or unrelated to career. \
117
- If the user is engaging in discussion, try to steer them towards getting in touch via email; ask for their email and record it using your record_user_details tool."
118
-
119
- system_prompt += f"\n\n## Summary:\n{self.summary}\n\n## LinkedIn Profile:\n{self.linkedin}\n\n"
120
- system_prompt += f"With this context, please chat with the user, always staying in character as {self.name}."
121
- return system_prompt
122
-
123
- def chat(self, message, history):
124
- messages = [{"role": "system", "content": self.system_prompt()}] + history + [{"role": "user", "content": message}]
125
- done = False
126
- while not done:
127
- response = self.openai.chat.completions.create(model="gpt-4o-mini", messages=messages, tools=tools)
128
- if response.choices[0].finish_reason == "tool_calls":
129
- message = response.choices[0].message
130
- tool_calls = message.tool_calls
131
- results = self.handle_tool_call(tool_calls)
132
- messages.append(message)
133
- messages.extend(results)
134
- else:
135
- done = True
136
- return response.choices[0].message.content
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
  if __name__ == "__main__":
139
- me = Me()
140
- gr.ChatInterface(me.chat, type="messages").launch()
 
6
  from PyPDF2 import PdfReader
7
  import gradio as gr
8
  import gdown
9
+ from datetime import datetime
10
+ from pathlib import Path
11
 
12
  load_dotenv(override=True)
13
 
14
  def push(text):
15
+ try:
16
+ requests.post(
17
+ "https://api.pushover.net/1/messages.json",
18
+ data={
19
+ "token": os.getenv("PUSHOVER_TOKEN"),
20
+ "user": os.getenv("PUSHOVER_USER"),
21
+ "message": text,
22
+ }
23
+ )
24
+ except Exception as e:
25
+ print(f"Pushover error: {e}")
26
 
27
  def record_user_details(email, name="Name not provided", notes="not provided"):
28
  push(f"Recording {name} with email {email} and notes {notes}")
 
38
  "parameters": {
39
  "type": "object",
40
  "properties": {
41
+ "email": {"type": "string", "description": "Their email address"},
42
+ "name": {"type": "string", "description": "Their name"},
43
+ "notes": {"type": "string", "description": "Conversation context"}
 
 
 
 
 
 
 
 
 
44
  },
45
  "required": ["email"],
46
  "additionalProperties": False
 
49
 
50
  record_unknown_question_json = {
51
  "name": "record_unknown_question",
52
+ "description": "Record questions that couldn't be answered",
53
  "parameters": {
54
  "type": "object",
55
  "properties": {
56
+ "question": {"type": "string", "description": "The unknown question"},
 
 
 
57
  },
58
  "required": ["question"],
59
  "additionalProperties": False
60
  }
61
  }
62
 
63
+ tools = [
64
+ {"type": "function", "function": record_user_details_json},
65
+ {"type": "function", "function": record_unknown_question_json}
66
+ ]
67
 
68
  class Me:
 
69
  def __init__(self):
70
  self.openai = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
71
  self.name = "Jacob Isaacson"
72
+ self.session_log = []
73
+ Path("chat_logs").mkdir(exist_ok=True)
74
 
75
+ # Download LinkedIn PDF
76
  linkedin_id = "1xz2RowkImpI8odYv8zvKdlRHaKfILn40"
77
+ gdown.download(f"https://drive.google.com/uc?id={linkedin_id}", "linkedin.pdf", quiet=False)
78
+ reader = PdfReader("linkedin.pdf")
79
+ self.linkedin = "".join(page.extract_text() or "" for page in reader.pages)
80
 
81
+ # Download summary.txt
 
 
 
 
 
 
82
  summary_id = "1hjJz082YFSVjFtpO0pwT6Tyy3eLYYj6-"
83
+ gdown.download(f"https://drive.google.com/uc?id={summary_id}", "summary.txt", quiet=False)
84
+ with open("summary.txt", "r", encoding="utf-8") as f:
 
 
85
  self.summary = f.read()
86
 
87
+ def system_prompt(self):
88
+ return f"""You are acting as {self.name}. You're answering questions on {self.name}'s website about his career, experience, and skills.
89
+ Be professional and conversational, as if talking to a potential employer or client.
90
+
91
+ If you can't answer something, call `record_unknown_question`. If a user seems interested, ask for their email and use `record_user_details`.
92
+
93
+ ## Summary:
94
+ {self.summary}
95
+
96
+ ## LinkedIn Profile:
97
+ {self.linkedin}
98
+ """
99
+
100
  def handle_tool_call(self, tool_calls):
101
  results = []
102
  for tool_call in tool_calls:
103
  tool_name = tool_call.function.name
104
  arguments = json.loads(tool_call.function.arguments)
 
105
  tool = globals().get(tool_name)
106
  result = tool(**arguments) if tool else {}
107
+ results.append({"role": "tool", "tool_call_id": tool_call.id, "content": json.dumps(result)})
108
  return results
109
 
110
+ def chat_stream(self, message, history):
111
+ messages = [{"role": "system", "content": self.system_prompt()}]
112
+ for user, assistant in history:
113
+ messages.append({"role": "user", "content": user})
114
+ messages.append({"role": "assistant", "content": assistant})
115
+
116
+ messages.append({"role": "user", "content": message})
117
+ self.session_log.append({"role": "user", "content": message})
118
+
119
+ stream = self.openai.chat.completions.create(
120
+ model="gpt-4o",
121
+ messages=messages,
122
+ tools=tools,
123
+ stream=True
124
+ )
125
+
126
+ full_response = ""
127
+ for chunk in stream:
128
+ delta = chunk.choices[0].delta
129
+ if hasattr(delta, "content") and delta.content:
130
+ full_response += delta.content
131
+ yield full_response
132
+
133
+ self.session_log.append({"role": "assistant", "content": full_response})
134
+ self.save_session_log()
135
+
136
+ def save_session_log(self):
137
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
138
+ filename = f"chat_logs/session_{timestamp}.json"
139
+ with open(filename, "w", encoding="utf-8") as f:
140
+ json.dump(self.session_log, f, indent=2)
141
+
142
+ me = Me()
143
+
144
+ with gr.Blocks(title="Jacob Isaacson Chatbot") as iface:
145
+ with gr.Row():
146
+ gr.Image("jacob.png", width=120, show_label=False)
147
+ gr.Markdown("### Chat with Jacob Isaacson\nAsk about Jacob's background, skills, or career. \n🛡️ *Your chat will be logged for quality and improvement purposes.*")
148
+
149
+ gr.ChatInterface(
150
+ fn=me.chat_stream,
151
+ chatbot=gr.Chatbot(show_copy_button=True),
152
+ examples=["What is Jacob's experience with AI?", "Tell me about his recent projects."],
153
+ retry_btn="🔁 Retry",
154
+ clear_btn="🗑️ Clear",
155
+ submit_btn="💬 Send",
156
+ )
157
 
158
  if __name__ == "__main__":
159
+ iface.launch()
160
+