Updated UI with title and description

#1
by kanlo - opened
Files changed (1) hide show
  1. app.py +146 -138
app.py CHANGED
@@ -1,139 +1,147 @@
1
- from dotenv import load_dotenv
2
- from openai import OpenAI
3
- import json
4
- import os
5
- import requests
6
- from pypdf import PdfReader
7
- import gradio as gr
8
-
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
- print(f"Recording user details: {name}, {email}, {notes}", flush=True)
24
- push(f"Recording {name} with email {email} and notes {notes}")
25
- return {"recorded": "ok"}
26
-
27
- def record_unknown_question(question):
28
- print(f"Recording unknown question: {question}", flush=True)
29
- push(f"Recording {question}")
30
- return {"recorded": "ok"}
31
-
32
- record_user_details_json = {
33
- "name": "record_user_details",
34
- "description": "Use this tool to record that a user is interested in being in touch and provided an email address",
35
- "parameters": {
36
- "type": "object",
37
- "properties": {
38
- "email": {
39
- "type": "string",
40
- "description": "The email address of this user"
41
- },
42
- "name": {
43
- "type": "string",
44
- "description": "The user's name, if they provided it"
45
- }
46
- ,
47
- "notes": {
48
- "type": "string",
49
- "description": "Any additional information about the conversation that's worth recording to give context"
50
- }
51
- },
52
- "required": ["email"],
53
- "additionalProperties": False
54
- }
55
- }
56
-
57
- record_unknown_question_json = {
58
- "name": "record_unknown_question",
59
- "description": "Always use this tool to record any question that couldn't be answered as you didn't know the answer",
60
- "parameters": {
61
- "type": "object",
62
- "properties": {
63
- "question": {
64
- "type": "string",
65
- "description": "The question that couldn't be answered"
66
- },
67
- },
68
- "required": ["question"],
69
- "additionalProperties": False
70
- }
71
- }
72
-
73
- tools = [{"type": "function", "function": record_user_details_json},
74
- {"type": "function", "function": record_unknown_question_json}]
75
-
76
-
77
- class Me:
78
-
79
- def __init__(self):
80
- grok_api_key = os.getenv("GROK_API_KEY")
81
- self.openai = OpenAI(api_key=grok_api_key,base_url="https://api.x.ai/v1" )
82
- self.name = "Ken Lo"
83
- reader = PdfReader("me/linkedin.pdf")
84
- self.linkedin = ""
85
- for page in reader.pages:
86
- text = page.extract_text()
87
- if text:
88
- self.linkedin += text
89
- with open("me/summary.txt", "r", encoding="utf-8") as f:
90
- self.summary = f.read()
91
-
92
-
93
- def handle_tool_call(self, tool_calls):
94
- results = []
95
- for tool_call in tool_calls:
96
- tool_name = tool_call.function.name
97
- arguments = json.loads(tool_call.function.arguments)
98
- print(f"Tool called: {tool_name}", flush=True)
99
- tool = globals().get(tool_name)
100
- result = tool(**arguments) if tool else {}
101
- results.append({"role": "tool","content": json.dumps(result),"tool_call_id": tool_call.id})
102
- return results
103
-
104
- def system_prompt(self):
105
- system_prompt = f"You are acting as {self.name}. You are answering questions on {self.name}'s website, \
106
- particularly questions related to {self.name}'s career, background, skills and experience. \
107
- Your responsibility is to represent {self.name} for interactions on the website as faithfully as possible. \
108
- You are given a summary of {self.name}'s background and LinkedIn profile which you can use to answer questions. \
109
- Be professional and engaging, as if talking to a potential client or future employer who came across the website. \
110
- 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. \
111
- 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. "
112
-
113
- system_prompt += f"\n\n## Summary:\n{self.summary}\n\n## LinkedIn Profile:\n{self.linkedin}\n\n"
114
- system_prompt += f"With this context, please chat with the user, always staying in character as {self.name}."
115
- return system_prompt
116
-
117
- def chat(self, message, history):
118
- messages = [{"role": "system", "content": self.system_prompt()}] + history + [{"role": "user", "content": message}]
119
- done = False
120
- while not done:
121
- response = self.openai.chat.completions.create(model="grok-3-mini", messages=messages,
122
- tools=tools,tool_choice="auto")
123
- print(f"Response: {response}", flush=True)
124
- if response.choices[0].message.tool_calls:
125
- print("Tool calls detected, processing...", flush=True)
126
- message = response.choices[0].message
127
- tool_calls = message.tool_calls
128
- results = self.handle_tool_call(tool_calls)
129
- messages.append(message)
130
- messages.extend(results)
131
- else:
132
- done = True
133
- return response.choices[0].message.content
134
-
135
-
136
- if __name__ == "__main__":
137
- me = Me()
138
- gr.ChatInterface(me.chat, type="messages").launch()
 
 
 
 
 
 
 
 
139
 
 
1
+ from dotenv import load_dotenv
2
+ from openai import OpenAI
3
+ import json
4
+ import os
5
+ import requests
6
+ from pypdf import PdfReader
7
+ import gradio as gr
8
+
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
+ print(f"Recording user details: {name}, {email}, {notes}", flush=True)
24
+ push(f"Recording {name} with email {email} and notes {notes}")
25
+ return {"recorded": "ok"}
26
+
27
+ def record_unknown_question(question):
28
+ print(f"Recording unknown question: {question}", flush=True)
29
+ push(f"Recording {question}")
30
+ return {"recorded": "ok"}
31
+
32
+ record_user_details_json = {
33
+ "name": "record_user_details",
34
+ "description": "Use this tool to record that a user is interested in being in touch and provided an email address",
35
+ "parameters": {
36
+ "type": "object",
37
+ "properties": {
38
+ "email": {
39
+ "type": "string",
40
+ "description": "The email address of this user"
41
+ },
42
+ "name": {
43
+ "type": "string",
44
+ "description": "The user's name, if they provided it"
45
+ }
46
+ ,
47
+ "notes": {
48
+ "type": "string",
49
+ "description": "Any additional information about the conversation that's worth recording to give context"
50
+ }
51
+ },
52
+ "required": ["email"],
53
+ "additionalProperties": False
54
+ }
55
+ }
56
+
57
+ record_unknown_question_json = {
58
+ "name": "record_unknown_question",
59
+ "description": "Always use this tool to record any question that couldn't be answered as you didn't know the answer",
60
+ "parameters": {
61
+ "type": "object",
62
+ "properties": {
63
+ "question": {
64
+ "type": "string",
65
+ "description": "The question that couldn't be answered"
66
+ },
67
+ },
68
+ "required": ["question"],
69
+ "additionalProperties": False
70
+ }
71
+ }
72
+
73
+ tools = [{"type": "function", "function": record_user_details_json},
74
+ {"type": "function", "function": record_unknown_question_json}]
75
+
76
+
77
+ class Me:
78
+
79
+ def __init__(self):
80
+ grok_api_key = os.getenv("GROK_API_KEY")
81
+ self.openai = OpenAI(api_key=grok_api_key,base_url="https://api.x.ai/v1" )
82
+ self.name = "Ken Lo"
83
+ reader = PdfReader("me/linkedin.pdf")
84
+ self.linkedin = ""
85
+ for page in reader.pages:
86
+ text = page.extract_text()
87
+ if text:
88
+ self.linkedin += text
89
+ with open("me/summary.txt", "r", encoding="utf-8") as f:
90
+ self.summary = f.read()
91
+
92
+
93
+ def handle_tool_call(self, tool_calls):
94
+ results = []
95
+ for tool_call in tool_calls:
96
+ tool_name = tool_call.function.name
97
+ arguments = json.loads(tool_call.function.arguments)
98
+ print(f"Tool called: {tool_name}", flush=True)
99
+ tool = globals().get(tool_name)
100
+ result = tool(**arguments) if tool else {}
101
+ results.append({"role": "tool","content": json.dumps(result),"tool_call_id": tool_call.id})
102
+ return results
103
+
104
+ def system_prompt(self):
105
+ system_prompt = f"You are acting as {self.name}. You are answering questions on {self.name}'s website, \
106
+ particularly questions related to {self.name}'s career, background, skills and experience. \
107
+ Your responsibility is to represent {self.name} for interactions on the website as faithfully as possible. \
108
+ You are given a summary of {self.name}'s background and LinkedIn profile which you can use to answer questions. \
109
+ Be professional and engaging, as if talking to a potential client or future employer who came across the website. \
110
+ 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. \
111
+ 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. "
112
+
113
+ system_prompt += f"\n\n## Summary:\n{self.summary}\n\n## LinkedIn Profile:\n{self.linkedin}\n\n"
114
+ system_prompt += f"With this context, please chat with the user, always staying in character as {self.name}."
115
+ return system_prompt
116
+
117
+ def chat(self, message, history):
118
+ messages = [{"role": "system", "content": self.system_prompt()}] + history + [{"role": "user", "content": message}]
119
+ done = False
120
+ while not done:
121
+ response = self.openai.chat.completions.create(model="grok-3-mini", messages=messages,
122
+ tools=tools,tool_choice="auto")
123
+ print(f"Response: {response}", flush=True)
124
+ if response.choices[0].message.tool_calls:
125
+ print("Tool calls detected, processing...", flush=True)
126
+ message = response.choices[0].message
127
+ tool_calls = message.tool_calls
128
+ results = self.handle_tool_call(tool_calls)
129
+ messages.append(message)
130
+ messages.extend(results)
131
+ else:
132
+ done = True
133
+ return response.choices[0].message.content
134
+
135
+
136
+ if __name__ == "__main__":
137
+ me = Me()
138
+ demo = gr.ChatInterface(fn= me.chat,
139
+ type="messages",
140
+ title="Ken CV agent",
141
+ description="""Dynamic CV agent
142
+ powered by Grok that lets you explore my resume through an
143
+ interactive chat."""
144
+ )
145
+
146
+ demo.launch(show_error=True)
147