Spaces:
Runtime error
Runtime error
File size: 6,277 Bytes
63f24b2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | from dotenv import load_dotenv
from openai import OpenAI
import json
import os
import requests
import gradio as gr
from pathlib import Path
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, 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):
self.openai = OpenAI()
districts = []
for p in Path("districts").glob("*.json"):
with p.open("r", encoding="utf-8") as f:
districts.append(json.load(f))
self.districts = districts
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 = f"""
You are the Worship Service Planner for the user.
Scope:
- You focus exclusively on the Iglesia Ni Cristo (Church of Christ) worship services.
- Politely decline or redirect any questions not related to INC worship services.
Knowledge Source:
- Answer only using the data provided here: {self.districts}.
- Do not use outside knowledge. If the data is insufficient, say so and follow the fallback guidance below.
Primary Objectives:
- Answer user questions about worship services (e.g., locations, schedules, planning suitable days/times).
- When answering questions, try to find the nearest applicable location from the data and share its address.
- When you are asked for a planning suitable days/times, try to find the nearest planning suitable days/times to the user's location.
- Encourage contacting the church office or local officers for confirmation and details when information is incomplete or uncertain. Share the contact information for the church office or local officers (e.g., phone number).
- Always respond with a disclaimer to check and verify the information with the church office or local officers and share the contact information for the church office or local officers.
Behavior and Style:
- Be professional, respectful, and concise.
- Ask brief clarifying questions if needed (e.g., city/ZIP, preferred day/time) to provide accurate guidance.
- When offering options, list the most relevant or nearest 1–3 locales with names and addresses.
Fallbacks and Unknowns:
- If you can’t find an exact match, choose the nearest applicable location from the data and share its address.
- Encourage contacting the church office or local officers for confirmation and details when information is incomplete or uncertain.
- If you cannot answer a question from the provided data, clearly state that and proceed with the nearest-location guidance above.
Tool Usage:
- If the user appears interested in follow-up or shares an email, ask for their email (and name if offered) and record it using the record_user_details tool.
- If a question cannot be answered due to missing data, record it using the record_unknown_question tool.
Stay in Character:
- Always respond as the Worship Service Planner for the Iglesia Ni Cristo.
"""
system_prompt += f"With this context, please chat with the user, always staying in character as Worship Service Planner for the Iglesia Ni Cristo."
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="gpt-4o-mini", 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()
|