Compare commits
No commits in common. "337cd46f24b5c65b2b6ccbb5f9d380bb90926a5b" and "2bd87f64030103cb2792c51c5da9b84e9d8c7889" have entirely different histories.
337cd46f24
...
2bd87f6403
11 changed files with 199 additions and 779 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,4 +1,3 @@
|
||||||
data.json
|
data.json
|
||||||
session.txt
|
session.txt
|
||||||
__pycache__
|
__pycache__
|
||||||
easyappointments-flow.md
|
|
19
README.md
19
README.md
|
@ -9,23 +9,16 @@
|
||||||
4. Create your own questions & answers and setup your keywords
|
4. Create your own questions & answers and setup your keywords
|
||||||
5. Run the bot `python main.py`
|
5. Run the bot `python main.py`
|
||||||
|
|
||||||
## Docker container
|
## details
|
||||||
1. `docker build -t matrix-nerve .`
|
|
||||||
2. `docker run -it matrix-nerve`
|
|
||||||
|
|
||||||
You may want to set data.json as a volume to be able to make changes on the fly
|
|
||||||
|
|
||||||
## Details
|
|
||||||
|
|
||||||
* The bot will listen to `!faq` and post the entire FAQ
|
* The bot will listen to `!faq` and post the entire FAQ
|
||||||
![Adding questions from matrix](screenshots/adding-questions.gif)
|
* Based on selected keywords it will include relevant questions & answers
|
||||||
|
|
||||||
|
![matrix room screenshot](screenshots/example.png)
|
||||||
|
|
||||||
## Features in the works
|
### Knock-knock jokes now supported!
|
||||||
* Alerts
|
|
||||||
* Dynamic configuration
|
![matrix room screenshot](screenshots/example2.png)
|
||||||
* Meeting requests (through easyappointments)
|
|
||||||
* Configurable API calls
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
514
commands.py
514
commands.py
|
@ -1,435 +1,153 @@
|
||||||
import random
|
import random
|
||||||
import features
|
jokes = [
|
||||||
import json
|
["Testing","Testing you!"],
|
||||||
|
["singing pokemon","Jiggalypuff! 🎙️"]
|
||||||
|
]
|
||||||
|
#jokes = []
|
||||||
|
|
||||||
api = features.API()
|
def handle_command(state,message):
|
||||||
debug = False
|
|
||||||
|
|
||||||
def handle_command(sender, message):
|
|
||||||
state = api.get_user_state(sender)
|
|
||||||
for command in commands:
|
for command in commands:
|
||||||
if message.find(command) == 0:
|
if message.find(command)==0:
|
||||||
result = commands[command](state, message, sender)
|
result = commands[command](state,message)
|
||||||
return result
|
return result
|
||||||
if len(state) > 0:
|
if len(state) > 0:
|
||||||
if debug == 1:
|
|
||||||
return commands[state[0]](state, message, sender)
|
|
||||||
try:
|
try:
|
||||||
result = commands[state[0]](state, message, sender)
|
result = commands[state[0]](state,message)
|
||||||
return result
|
return result
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if __name__ != '__main__':
|
|
||||||
state = []
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
return {
|
return {
|
||||||
"response": f"⚠️Error⚠️\n{e}"
|
"state":[],
|
||||||
|
"response":f"⚠️Error⚠️ \n {e}"
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
"response": "",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def get_faq_string():
|
|
||||||
return api.get_faq_string()
|
|
||||||
|
|
||||||
|
|
||||||
def nevermind(state, message, sender):
|
|
||||||
api.update_user_state(sender, [])
|
|
||||||
return {
|
|
||||||
"response": "starting over."
|
|
||||||
}
|
|
||||||
|
|
||||||
# faq
|
|
||||||
|
|
||||||
|
|
||||||
def get_faq(state, message, sender):
|
|
||||||
if len(state) == 0:
|
|
||||||
return {
|
|
||||||
"response": api.get_faq_string()
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
"response": api.get_faq_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def add_question(state, message, sender):
|
|
||||||
if len(state) == 0:
|
|
||||||
api.update_user_state(sender, ["!add question"])
|
|
||||||
return {
|
|
||||||
'response': "Please enter the question title."
|
|
||||||
}
|
|
||||||
elif len(state) == 1:
|
|
||||||
state.append(message)
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
return {
|
|
||||||
'response': 'Please enter the answer to the question.'
|
|
||||||
}
|
|
||||||
elif len(state) == 2:
|
|
||||||
state.append(message)
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
state = api.get_user_state(sender)
|
|
||||||
return {
|
|
||||||
'response': f"Your question is:\n---\n# {state[1]}\n{state[2]}\n\n---\nIf this is what you want respond with `confirm`\n If you'd like to start over respond with `restart`\n Respond with `nevermind` to cancel entirely"
|
|
||||||
}
|
|
||||||
elif len(state) == 3:
|
|
||||||
if message == 'confirm':
|
|
||||||
api.add_question({
|
|
||||||
'question': state[1],
|
|
||||||
'answer': state[2]
|
|
||||||
})
|
|
||||||
api.update_user_state(sender, [])
|
|
||||||
return {
|
|
||||||
'response': 'Question added.'
|
|
||||||
}
|
|
||||||
elif message == 'restart':
|
|
||||||
api.update_user_state(sender, ['!add question'])
|
|
||||||
return {
|
|
||||||
'response': 'Please enter the question title.'
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
return {
|
|
||||||
'response': f"Your question is:\n# {state[1]}\n{state[2]}\n\nIf this is what you want respond with `confirm`\n If you'd like to start over respond with `restart`\n Respond with `nevermind` to cancel entirely"
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
'response': None
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def update_question(state, message, sender):
|
|
||||||
if len(api.data['faq']['questions']) == 0:
|
|
||||||
api.update_user_state(sender, [])
|
|
||||||
return {
|
|
||||||
'response': "No questions registered."
|
|
||||||
}
|
|
||||||
elif len(state)==0:
|
|
||||||
api.update_user_state(sender,"!update question")
|
|
||||||
return {
|
|
||||||
"response":f"Choose a question to update:\n {api.get_faq_questions}"
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
'response': None,
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def remove_question(state, message, sender):
|
|
||||||
if len(api.data['faq']['questions']) == 0:
|
|
||||||
api.update_user_state(sender, [])
|
|
||||||
return {
|
|
||||||
'response': "No questions registered."
|
|
||||||
}
|
|
||||||
elif len(state)==0:
|
|
||||||
api.update_user_state(sender,["!remove question"])
|
|
||||||
return {
|
|
||||||
"response":f"Choose a question to remove:\n {api.get_faq_questions()}"
|
|
||||||
}
|
|
||||||
elif len(state) == 1:
|
|
||||||
try:
|
|
||||||
int(message)
|
|
||||||
except:
|
|
||||||
return {"response":"Please enter a number."}
|
|
||||||
state.append(message)
|
|
||||||
if int(state[1]) < len(api.data['faq']['questions']) and int(state[1]) >=0:
|
|
||||||
if debug == True:
|
|
||||||
api.remove_question(int(state[1]))
|
|
||||||
api.update_user_state(sender,[])
|
|
||||||
return {
|
|
||||||
'response':'Question removed'
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
api.update_user_state(sender,[])
|
|
||||||
api.remove_question(int(state[1]))
|
|
||||||
return {
|
|
||||||
'response':'Question removed'
|
|
||||||
}
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
api.update_user_state(sender,["!remove question"])
|
|
||||||
return {
|
|
||||||
'response':'Please enter the correct question #'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'response': None,
|
"response":None,
|
||||||
|
"state":state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
def update_header(state, message, sender):
|
Knock-knock implimentation
|
||||||
|
|
||||||
|
when you receive message, read state.
|
||||||
|
user: knock knock
|
||||||
|
bot: who's there? -> bot responds and registers state
|
||||||
|
(user.state=[knock-knock])
|
||||||
|
user: {statement}
|
||||||
|
bot: {statement} who? -> bot responds and stores statement
|
||||||
|
(user.stage=[knock-knock,{statement}])
|
||||||
|
user: {punchline}
|
||||||
|
bot: Nice one! -> bot saves knock-knock joke
|
||||||
|
"""
|
||||||
|
|
||||||
|
def nevermind(state,message):
|
||||||
return {
|
return {
|
||||||
'response': None,
|
"response":"starting over.",
|
||||||
|
"state":[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def knock_knock(state,message):
|
||||||
def remove_header(state, message, sender):
|
#return {response:"",state:""}
|
||||||
return {
|
try:
|
||||||
'response': None,
|
if state[0] != "knock knock":
|
||||||
|
#clear the state
|
||||||
}
|
state = []
|
||||||
|
except:
|
||||||
|
pass
|
||||||
def update_footer(state, message, sender):
|
if len(state) == 0:
|
||||||
return {
|
state.append("knock knock")
|
||||||
'response': None,
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def remove_footer(state, message, sender):
|
|
||||||
return {
|
|
||||||
'response': None,
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def add_admin(state, message, sender):
|
|
||||||
return {
|
|
||||||
'response': None,
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def remove_admin(state, message, sender):
|
|
||||||
return {
|
|
||||||
'response': None,
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def meetings(state,message,sender):
|
|
||||||
return {
|
|
||||||
'response':api.appointments.list_upcoming_appointments(sender)
|
|
||||||
}
|
|
||||||
|
|
||||||
def register_customer(state,message,sender):
|
|
||||||
if api.appointments.is_customer(sender):
|
|
||||||
return {'response':"Already registered."}
|
|
||||||
if state == ['!register2']:
|
|
||||||
return {
|
return {
|
||||||
'response':'What is your first name?'
|
"response":"Who's there?",
|
||||||
}
|
"state": state
|
||||||
|
|
||||||
if state == []:
|
|
||||||
state = ['!register']
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
return {
|
|
||||||
'response':'What is your first name?'
|
|
||||||
}
|
}
|
||||||
if len(state) == 1:
|
if len(state) == 1:
|
||||||
state.append(message)
|
state.append(message)
|
||||||
api.update_user_state(sender, state)
|
|
||||||
return {
|
return {
|
||||||
'response':'What is your last name?'
|
"response":message + " who?",
|
||||||
|
"state":state
|
||||||
}
|
}
|
||||||
if len(state) == 2:
|
if len(state) == 2:
|
||||||
state.append(message)
|
state.append(message)
|
||||||
api.update_user_state(sender, state)
|
jokes.append([
|
||||||
|
state[1],state[2]
|
||||||
|
])
|
||||||
|
print("joke registered.")
|
||||||
return {
|
return {
|
||||||
'response':'What is your e-mail?'
|
"response":"Hah! very funny!",
|
||||||
|
"state":[]
|
||||||
}
|
}
|
||||||
if len(state) == 3:
|
|
||||||
state.append(message)
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
return {
|
|
||||||
'response':"What is your phone number?"
|
|
||||||
}
|
|
||||||
if len(state) == 4:
|
|
||||||
state.append(message)
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
resp = f"You've entered: `{state[1]} {state[2]} ({state[3]} / {state[4]})`\n**Is this correct?**\nIf so, respond with:Yes\nIf not, to restart respond with :No\nYou can always cancel with:nevermind"
|
|
||||||
return {
|
|
||||||
'response':resp
|
|
||||||
}
|
|
||||||
if len(state) == 5:
|
|
||||||
if "yes" in message.lower():
|
|
||||||
data = {
|
|
||||||
"firstName":state[1],
|
|
||||||
"lastName":state[2],
|
|
||||||
"email":state[3],
|
|
||||||
"phone":state[4],
|
|
||||||
"notes":f"matrix:{sender}"
|
|
||||||
}
|
|
||||||
if sender == "admin":
|
|
||||||
dat = json.dumps(data)
|
|
||||||
print(f"Data:\n{dat}")
|
|
||||||
if api.appointments.register_customer(data):
|
|
||||||
if(state[0]=='!register2'):
|
|
||||||
state = ['!book']
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
return {'response':"Successfully registered.\n\n"+booking(['!book'],'',sender)['response']}
|
|
||||||
state = []
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
return{'response':"Successfully registered."}
|
|
||||||
else:
|
|
||||||
return{'response':"Error, please try again."}
|
|
||||||
api.update_user_state(sender, [])
|
|
||||||
return {
|
|
||||||
'response':''
|
|
||||||
}
|
|
||||||
|
|
||||||
def select_service(state,message,sender):
|
|
||||||
if len(state) >= 2:
|
|
||||||
return select_provider(state, message, sender)
|
|
||||||
# ['!book','select-service']
|
|
||||||
if message == "!book":
|
|
||||||
return {'response':api.select_service()}
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
state.append(api.appointments.get_services()[int(message)]['id'])
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
return booking(state, "", sender)
|
|
||||||
except:
|
|
||||||
return {'response':'Error selecting service\nTo cancel type:nevermind'}
|
|
||||||
|
|
||||||
def select_provider(state,message,sender):
|
|
||||||
if len(state) >= 3:
|
|
||||||
return select_time(state, message, sender)
|
|
||||||
if message == "":
|
|
||||||
return {'response':api.select_provider()}
|
|
||||||
try:
|
|
||||||
state.append(api.appointments.get_providers()[int(message)]['id'])
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
return booking(state,"",sender)
|
|
||||||
except:
|
|
||||||
return {'response':'Error selecting provider\nTo cancel type:nevermind'}
|
|
||||||
|
|
||||||
|
|
||||||
def select_time(state,message,sender):
|
|
||||||
if len(state) >= 5:
|
|
||||||
return booking(state, message, sender)
|
|
||||||
api.update_data()
|
|
||||||
# ['!book','select-time']
|
|
||||||
if len(state) == 3:
|
|
||||||
msg = api.select_times(state[1],state[2],message)
|
|
||||||
if msg == False:
|
|
||||||
return {'response':"Please enter a date you'd like to book (\"YYYY-MM-DD\" format)"}
|
|
||||||
state.append(message)
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
return {'response':msg}
|
|
||||||
if len(state) == 4:
|
|
||||||
times = api.appointments.get_availabilities(state[1], state[2], state[3])
|
|
||||||
if message in times:
|
|
||||||
state.append(message)
|
|
||||||
time = None
|
|
||||||
try:
|
|
||||||
time = times[int(message)-1]
|
|
||||||
state.append(time)
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
return booking(state, message, sender)
|
|
||||||
except:
|
|
||||||
return {'response':api.select_times(state[1],state[2],state[3])}
|
|
||||||
return {'response':error}
|
|
||||||
|
|
||||||
def booking(state,message,sender):
|
|
||||||
if len(state) > 5:
|
|
||||||
state = []
|
|
||||||
if state==[]:
|
|
||||||
state.append("!book")
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
"""
|
|
||||||
To book an appointment, you need (in order):
|
|
||||||
* the customer ID (now mapped to mxid) (0?)
|
|
||||||
* The service id (1)
|
|
||||||
* the provider id (2)
|
|
||||||
* the start date & time (3)
|
|
||||||
"""
|
|
||||||
#Quick checks
|
|
||||||
customer = api.appointments.is_customer(sender)
|
|
||||||
if customer == False:
|
|
||||||
return register_customer([], "", sender)
|
|
||||||
|
|
||||||
#Service check
|
|
||||||
service = None
|
|
||||||
if len(api.appointments.services) == 0:
|
|
||||||
return {'response':"Error: there are no services"}
|
|
||||||
if len(api.appointments.services) == 1:
|
|
||||||
service = api.appointments.get_services()[0]
|
|
||||||
state.append(service)
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
return booking(state, message, sender)
|
|
||||||
if len(state) >= 2:
|
|
||||||
service = state[1]
|
|
||||||
if service == None:
|
|
||||||
return select_service(state, message, sender)
|
|
||||||
|
|
||||||
|
|
||||||
#Provider check
|
|
||||||
|
|
||||||
provider = None
|
|
||||||
if len(api.appointments.providers) == 0:
|
|
||||||
return {'response':'error: there are no providers'}
|
|
||||||
if len(state) >= 3:
|
|
||||||
provider = state[2]
|
|
||||||
elif len(api.appointments.providers) == 1:
|
|
||||||
provider = api.appointments.get_providers()[0]['id']
|
|
||||||
if service != None:
|
|
||||||
state.append(provider)
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
if provider == None:
|
|
||||||
return select_provider(state, message, sender)
|
|
||||||
|
|
||||||
time = None
|
|
||||||
if len(state) == 5:
|
|
||||||
time = state[4]
|
|
||||||
if time == None:
|
|
||||||
return select_time(state, message, sender)
|
|
||||||
data = {
|
|
||||||
"start": state[3] + " "+ state[4]+":00",
|
|
||||||
"customerId":int(customer),
|
|
||||||
"providerId":int(provider),
|
|
||||||
"serviceId":int(service)
|
|
||||||
}
|
|
||||||
result = api.appointments.register_appointment(data)
|
|
||||||
if result != False:
|
|
||||||
state = []
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
return{'response':'Successfully registered appointment!'}
|
|
||||||
else:
|
|
||||||
state = []
|
|
||||||
api.update_user_state(sender, state)
|
|
||||||
print(result)
|
|
||||||
return{'response':"Error: please try again"}
|
|
||||||
|
|
||||||
return{'response':"Error: please try again"}
|
|
||||||
|
|
||||||
|
|
||||||
def services(state,message,sender):
|
|
||||||
return {
|
return {
|
||||||
'response':api.list_services()
|
"response":"Cleared.",
|
||||||
|
"state":[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""'joke' command
|
||||||
|
-------------
|
||||||
|
user:!joke
|
||||||
|
bot:Knock knock -> bot initializes state
|
||||||
|
(user.state=[joke])
|
||||||
|
user: Who's there?
|
||||||
|
bot: {statement} -> bot responds with chosen joke
|
||||||
|
(user.state=[joke,chosenjoke])
|
||||||
|
user: {statement} who?
|
||||||
|
bot:
|
||||||
|
|
||||||
|
"""
|
||||||
|
def joke(state,message):
|
||||||
|
if len(jokes) == 0:
|
||||||
|
return {
|
||||||
|
"response":"I don't know any jokes...",
|
||||||
|
"state":[]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(state) == 0:
|
||||||
|
return {
|
||||||
|
"response":"Knock knock",
|
||||||
|
"state":["joke"]
|
||||||
|
}
|
||||||
|
elif len(state) == 1:
|
||||||
|
if message.find("there?") > 0 :
|
||||||
|
#get random joke index
|
||||||
|
state.append(random.randint(0,len(jokes)-1))
|
||||||
|
return {
|
||||||
|
"response":jokes[state[1]][0],
|
||||||
|
"state":state
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return {
|
||||||
|
"response":"ask, \"who's there?\"",
|
||||||
|
"state":state
|
||||||
|
}
|
||||||
|
elif len(state) == 2:
|
||||||
|
if message.find("who?") > 0:
|
||||||
|
return {
|
||||||
|
"response":jokes[state[1]][1],
|
||||||
|
"state":[]
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return {
|
||||||
|
"response":"ask, \""+ jokes[state[1]][0] +" who?\"",
|
||||||
|
"state":state
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"response":None,
|
||||||
|
"state":[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
commands = {
|
commands = {
|
||||||
"nevermind": nevermind,
|
"nevermind":nevermind,
|
||||||
"!faq": get_faq,
|
"knock knock":knock_knock,
|
||||||
"!add question": add_question,
|
"joke":joke
|
||||||
"!remove question": remove_question,
|
|
||||||
"!update question": update_question,
|
|
||||||
"!update header": update_header,
|
|
||||||
"!remove header": remove_header,
|
|
||||||
"!update footer": update_footer,
|
|
||||||
"!remove footer": remove_footer,
|
|
||||||
"!add admin": add_admin,
|
|
||||||
"!remove admin": remove_admin,
|
|
||||||
"!meetings":meetings,
|
|
||||||
"!register":register_customer,
|
|
||||||
"!register2":register_customer,
|
|
||||||
"!book":booking,
|
|
||||||
"!services":services
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
user = "admin"
|
|
||||||
msg = ""
|
msg = ""
|
||||||
debug = True
|
|
||||||
while msg != "exit":
|
while msg != "exit":
|
||||||
msg = input("user:")
|
msg = input("user:")
|
||||||
print("bot:"+handle_command(user, msg)['response'])
|
user = handle_command(user,msg)
|
||||||
# print("state:",user)
|
#print("state:",user)
|
||||||
|
|
|
@ -2,24 +2,20 @@
|
||||||
"username": "bot",
|
"username": "bot",
|
||||||
"password": "hunter2",
|
"password": "hunter2",
|
||||||
"homeserver": "http://localhost:8008",
|
"homeserver": "http://localhost:8008",
|
||||||
"easyappointments": {
|
|
||||||
"token": "secrettoken",
|
|
||||||
"url": "http://localhost/easyappointments/index.php"
|
|
||||||
},
|
|
||||||
"faq": {
|
"faq": {
|
||||||
"header": "# Simple example FAQ",
|
"header": "# Simple example FAQ",
|
||||||
"questions": [{
|
"questions": [{
|
||||||
"question": "What is the meaning of life?",
|
"question": "# What is the meaning of life?",
|
||||||
"answer": "42.",
|
"answer": "42.",
|
||||||
"key_phrases": ["meaning", "life"]
|
"key_phrases": ["meaning", "life"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"question": "Who is the coolest pokemon?",
|
"question": "# Who is the coolest pokemon?",
|
||||||
"answer": "Mewtwo! 🐈",
|
"answer": "Mewtwo! 🐈",
|
||||||
"key_phrases": ["coolest", "pokemon"]
|
"key_phrases": ["coolest", "pokemon"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"question": "What is the coolest programming language?",
|
"question": "# What is the coolest programming language?",
|
||||||
"answer": "🐍 python!",
|
"answer": "🐍 python!",
|
||||||
"key_phrases": ["coolest", "programming", "language"]
|
"key_phrases": ["coolest", "programming", "language"]
|
||||||
}
|
}
|
||||||
|
@ -27,7 +23,5 @@
|
||||||
"footer": "Brought to you by Nerve\nSee the [code](https://codeberg.org/gabe/Nerve)"
|
"footer": "Brought to you by Nerve\nSee the [code](https://codeberg.org/gabe/Nerve)"
|
||||||
|
|
||||||
},
|
},
|
||||||
"users": {},
|
"users": {}
|
||||||
"admins": [],
|
|
||||||
"meetings": []
|
|
||||||
}
|
}
|
|
@ -1,151 +0,0 @@
|
||||||
import requests,json
|
|
||||||
|
|
||||||
class easyappointments:
|
|
||||||
def __init__(self,token,url):
|
|
||||||
self.token = token
|
|
||||||
self.url = url
|
|
||||||
self.headers = {"Authorization":f"Bearer {token}"}
|
|
||||||
self.appointments = {}
|
|
||||||
self.services = {}
|
|
||||||
self.providers = {}
|
|
||||||
self.customers = {}
|
|
||||||
try:
|
|
||||||
self.update_data()
|
|
||||||
except:
|
|
||||||
print("Failed to connect to easyappointments!")
|
|
||||||
|
|
||||||
def get_appointments(self):
|
|
||||||
data = requests.get(self.url+'/api/v1/appointments',headers=self.headers)
|
|
||||||
return data.json()
|
|
||||||
def get_services(self):
|
|
||||||
data = requests.get(self.url+'/api/v1/services',headers=self.headers)
|
|
||||||
return data.json()
|
|
||||||
def get_providers(self):
|
|
||||||
data = requests.get(self.url+'/api/v1/providers',headers=self.headers)
|
|
||||||
return data.json()
|
|
||||||
def get_customers(self):
|
|
||||||
data = requests.get(self.url+'/api/v1/customers',headers=self.headers)
|
|
||||||
return data.json()
|
|
||||||
|
|
||||||
def get_availabilities(self,service,provider,date):
|
|
||||||
try:
|
|
||||||
data = requests.get(self.url+f"/api/v1/availabilities?serviceId={service}&providerId={provider}&date={date}",headers=self.headers)
|
|
||||||
return data.json()
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def update_data(self):
|
|
||||||
appointments = self.get_appointments()
|
|
||||||
for a in appointments:
|
|
||||||
self.appointments[a['id']] = a
|
|
||||||
services = self.get_services()
|
|
||||||
for s in services:
|
|
||||||
self.services[s['id']]=s
|
|
||||||
providers = self.get_providers()
|
|
||||||
for p in providers:
|
|
||||||
self.providers[p['id']]=p
|
|
||||||
customers = self.get_customers()
|
|
||||||
for c in customers:
|
|
||||||
self.customers[c['id']]=c
|
|
||||||
|
|
||||||
def is_customer(self,mxid):
|
|
||||||
customers = self.get_customers()
|
|
||||||
for c in customers:
|
|
||||||
if mxid in c['notes']:
|
|
||||||
return c['id']
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def is_provider(self,mxid):
|
|
||||||
providers = self.get_providers()
|
|
||||||
for p in providers:
|
|
||||||
if mxid in p['notes']:
|
|
||||||
return p['id']
|
|
||||||
return -1
|
|
||||||
def get_upcoming_appointments(self,mxid):
|
|
||||||
#get services & customers
|
|
||||||
id = self.is_provider(mxid)
|
|
||||||
if id:
|
|
||||||
apts = []
|
|
||||||
data = self.get_appointments()
|
|
||||||
for a in data:
|
|
||||||
if a['providerId'] == id:
|
|
||||||
apts.append(a)
|
|
||||||
return apts
|
|
||||||
else:
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def list_upcoming_appointments(self,mxid):
|
|
||||||
apts = self.get_upcoming_appointments(mxid)
|
|
||||||
if apts == []:
|
|
||||||
return "No meetings recorded."
|
|
||||||
output = ""
|
|
||||||
for a in apts:
|
|
||||||
service = self.services[a['serviceId']]['name']
|
|
||||||
customer = self.customers[a['customerId']]['firstName']
|
|
||||||
output += f"## {service} with {customer}\nTime:{a['start']}\n"
|
|
||||||
return output
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def register_customer(self,customer_data):
|
|
||||||
#customer data
|
|
||||||
"""
|
|
||||||
{
|
|
||||||
"firstName":"name",
|
|
||||||
"lastName":"name",
|
|
||||||
"email":"email",
|
|
||||||
"phone":"phone"
|
|
||||||
"notes":"matrix:mxid"
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
id = requests.post(self.url+'/api/v1/customers',headers=self.headers,data=json.dumps(customer_data)).json()['id']
|
|
||||||
self.update_data()
|
|
||||||
return id
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def register_appointment(self,appointment_data):
|
|
||||||
#appointment data
|
|
||||||
"""{
|
|
||||||
"start":"YY-MM-DD HH:MM:SS",
|
|
||||||
"customerId":9,
|
|
||||||
"providerId":4,
|
|
||||||
"serviceId:4
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
print("Registering appointment:")
|
|
||||||
print(json.dumps(appointment_data))
|
|
||||||
result = requests.post(
|
|
||||||
self.url+'/api/v1/appointments',
|
|
||||||
headers = self.headers,
|
|
||||||
data=json.dumps(appointment_data)
|
|
||||||
)
|
|
||||||
id = result.json()['id']
|
|
||||||
if id:
|
|
||||||
return id
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
cdat = {
|
|
||||||
"firstName":"Test",
|
|
||||||
"lastName":"",
|
|
||||||
"email":"test@testing.xa",
|
|
||||||
"phone":"888-888-8888",
|
|
||||||
"notes":"matrix:@lol:testing"
|
|
||||||
}
|
|
||||||
adat = {
|
|
||||||
"start":"2022-09-28 09:00:00",
|
|
||||||
"customerId":8,
|
|
||||||
"providerId":4,
|
|
||||||
"serviceId":2
|
|
||||||
}
|
|
||||||
|
|
||||||
easy = easyappointments('secrettoken', 'http://localhost:8787/easyappointments/index.php')
|
|
|
@ -1 +0,0 @@
|
||||||
Error:@gabriel:libresolutions.network: !bookError:@gabriel:libresolutions.network: !bookError:@gabriel:libresolutions.network: !register
|
|
0
faq.py
Normal file
0
faq.py
Normal file
188
features.py
188
features.py
|
@ -1,188 +0,0 @@
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
import easyappointments
|
|
||||||
import datetime
|
|
||||||
"""
|
|
||||||
Features
|
|
||||||
This is the main API for executing functions with data
|
|
||||||
"""
|
|
||||||
|
|
||||||
def check_date(date):
|
|
||||||
try:
|
|
||||||
datetime.datetime.strptime(date,"%Y-%m-%d")
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
class API:
|
|
||||||
def __init__(self):
|
|
||||||
with open('data.json') as f:
|
|
||||||
self.data = json.loads(f.read())
|
|
||||||
self.appointments = easyappointments.easyappointments(self.data['easyappointments']['token'], self.data['easyappointments']['url'])
|
|
||||||
# Only refresh data when a change is made
|
|
||||||
def update_data(self):
|
|
||||||
with open('data.json','r') as f:
|
|
||||||
self.data = json.loads(f.read())
|
|
||||||
|
|
||||||
def save(self):
|
|
||||||
with open('data.json','w') as f:
|
|
||||||
f.write(json.dumps(self.data,indent=2))
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
#Administration
|
|
||||||
def is_admin(self,handle):
|
|
||||||
#return bool
|
|
||||||
pass
|
|
||||||
def add_admin(self,handle):
|
|
||||||
#return bool
|
|
||||||
if self.is_admin(handle):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
self.data["admins"].append(handle)
|
|
||||||
self.save()
|
|
||||||
return True
|
|
||||||
def remove_admin(self,handle):
|
|
||||||
#return bool
|
|
||||||
if self.is_admin(handle):
|
|
||||||
i = self.data["admins"].index(handle)
|
|
||||||
self.data["admins"].pop(i)
|
|
||||||
self.save()
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
#state management
|
|
||||||
def get_user_state(self,handle):
|
|
||||||
if handle not in self.data["users"]:
|
|
||||||
self.data["users"][handle]={"state":[]}
|
|
||||||
self.save()
|
|
||||||
return self.data["users"][handle]["state"]
|
|
||||||
|
|
||||||
def update_user_state(self,handle,state):
|
|
||||||
self.update_data()
|
|
||||||
current_state = self.get_user_state(handle)
|
|
||||||
self.data["users"][handle]["state"] = state
|
|
||||||
self.save()
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
#FAQ
|
|
||||||
def get_faq_string(self):
|
|
||||||
faq = self.data["faq"]
|
|
||||||
return faq["header"] + "".join(
|
|
||||||
["\n# "+q["question"]+"\n"+q["answer"]+"\n" for q in faq["questions"]]
|
|
||||||
) + "\n"+ faq["footer"]
|
|
||||||
|
|
||||||
def get_faq_questions(self):
|
|
||||||
self.update_data()
|
|
||||||
questions = self.data['faq']['questions']
|
|
||||||
response = ""
|
|
||||||
index = 0
|
|
||||||
for question in questions:
|
|
||||||
response += f"[{index}]:{question['question']}\n"
|
|
||||||
index += 1
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_header(self):
|
|
||||||
self.update_data()
|
|
||||||
return self.data["faq"]["header"]
|
|
||||||
def set_header(self,hdr):
|
|
||||||
self.update_data()
|
|
||||||
#return bool
|
|
||||||
self.data["faq"]["header"] = hdr
|
|
||||||
self.save()
|
|
||||||
return True
|
|
||||||
def get_questions(self):
|
|
||||||
self.update_data()
|
|
||||||
#return questions
|
|
||||||
return self.data["faq"]["questions"]
|
|
||||||
def add_question(self,qtn):
|
|
||||||
self.update_data()
|
|
||||||
#return bool
|
|
||||||
self.data["faq"]["questions"].append(qtn)
|
|
||||||
self.save()
|
|
||||||
return True
|
|
||||||
def remove_question(self,qtn_i):
|
|
||||||
self.update_data()
|
|
||||||
#return bool
|
|
||||||
self.data["faq"]["questions"].pop(qtn_i)
|
|
||||||
self.save()
|
|
||||||
return True
|
|
||||||
def update_question(self,qtn_i,qtn):
|
|
||||||
self.update_data()
|
|
||||||
#return bool
|
|
||||||
self.data["faq"]["questions"][qtn_i]=qtn
|
|
||||||
return True
|
|
||||||
|
|
||||||
#Meetings
|
|
||||||
def get_meetings(self,mxid):
|
|
||||||
self.update_data()
|
|
||||||
self.appointments.list_upcoming_appointments(mxid)
|
|
||||||
pass
|
|
||||||
def list_services(self):
|
|
||||||
msg = "## Services:"
|
|
||||||
for i in self.appointments.services:
|
|
||||||
service = self.appointments.services[i]
|
|
||||||
name = service['name']
|
|
||||||
price = str(service['price']) + service['currency']
|
|
||||||
description = service['description']
|
|
||||||
msg += f"\n### {name}\nPrice:{price}\n{description}"
|
|
||||||
return msg
|
|
||||||
|
|
||||||
|
|
||||||
def select_service(self):
|
|
||||||
msg = "## Choose a service:"
|
|
||||||
counter = 1
|
|
||||||
for i in self.appointments.services:
|
|
||||||
service = self.appointments.services[i]
|
|
||||||
name = f"#{counter}: " + service['name']
|
|
||||||
price = str(service['price']) + service['currency']
|
|
||||||
description = service['description']
|
|
||||||
msg += f"\n### {name}\nPrice:{price}\n{description}"
|
|
||||||
counter += 1
|
|
||||||
msg += "\nPlease enter the # of the service:"
|
|
||||||
return msg
|
|
||||||
|
|
||||||
def select_provider(self):
|
|
||||||
msg = "## Choose a provider:"
|
|
||||||
counter = 1
|
|
||||||
for p in self.appointments.get_providers():
|
|
||||||
name = p['firstName']+" "+p['lastName']
|
|
||||||
msg += f"\n* #{counter}: {name}"
|
|
||||||
counter += 1
|
|
||||||
msg += "\nPlease enter the # of the provider"
|
|
||||||
return msg
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def select_times(self,service,provider,date):
|
|
||||||
data = self.appointments.get_availabilities(service, provider, date)
|
|
||||||
if data == False or check_date(date) == False:
|
|
||||||
return False
|
|
||||||
msg = f"## Choose a time for {date}:\n"
|
|
||||||
counter = 1
|
|
||||||
for t in data:
|
|
||||||
msg += f"{counter}){t} "
|
|
||||||
counter +=1
|
|
||||||
msg +="\nPlease enter the # of time"
|
|
||||||
return msg
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def request_meeting(self):
|
|
||||||
self.update_data()
|
|
||||||
pass
|
|
||||||
def accept_meeting(self):
|
|
||||||
self.update_data()
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
api = API()
|
|
||||||
print("Storage loaded.\n",api.data['username'])
|
|
1
knockknock.py
Normal file
1
knockknock.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
print("knock-knock functionality loaded")
|
87
main.py
87
main.py
|
@ -4,32 +4,87 @@ import simplematrixbotlib as botlib
|
||||||
import commands
|
import commands
|
||||||
|
|
||||||
data = json.loads(open('data.json').read())
|
data = json.loads(open('data.json').read())
|
||||||
|
dfaq = data["faq"]
|
||||||
|
userstate = data['users']
|
||||||
|
faq_text = dfaq["header"] + "".join(["\n"+q["question"]+"\n"+q["answer"]
|
||||||
|
for q in dfaq["questions"]]) + "\n\n"+dfaq["footer"]
|
||||||
|
|
||||||
creds = botlib.Creds(
|
creds = botlib.Creds(
|
||||||
data["homeserver"],
|
data["homeserver"],
|
||||||
data['username'],
|
data['username'],
|
||||||
data['password']
|
data['password']
|
||||||
)
|
)
|
||||||
bot = botlib.Bot(creds)
|
bot = botlib.Bot(creds)
|
||||||
|
PREFIX = '!'
|
||||||
|
|
||||||
|
|
||||||
|
def load_faq():
|
||||||
|
dfaq = json.loads(open('data.json').read())["faq"]
|
||||||
|
return dfaq["header"] + "".join(["\n"+q["question"]+"\n"+q["answer"] for q in dfaq["questions"]]) + "\n\n"+dfaq["footer"]
|
||||||
|
|
||||||
|
def save_userstate():
|
||||||
|
with open('data.json','w') as f:
|
||||||
|
f.write(json.dumps(data,indent=4))
|
||||||
|
|
||||||
@bot.listener.on_message_event
|
@bot.listener.on_message_event
|
||||||
async def message(room, message):
|
async def faq(room, message):
|
||||||
try:
|
if message.sender not in userstate:
|
||||||
result = commands.handle_command(message.sender, message.body)
|
userstate[message.sender] = {"state":[]}
|
||||||
if result['response'] != None and result['response'] != "":
|
save_userstate()
|
||||||
await bot.api.send_markdown_message(
|
|
||||||
room.room_id,
|
|
||||||
result['response']
|
state = userstate[message.sender]['state']
|
||||||
)
|
result = commands.handle_command(state,message.body)
|
||||||
except:
|
if result['response']!= None:
|
||||||
with open("error.log",'a') as f:
|
state = result['state']
|
||||||
f.write(f"Error:{message}")
|
userstate[message.sender]['state'] = result['state']
|
||||||
|
save_userstate()
|
||||||
|
await bot.api.send_markdown_message(
|
||||||
|
room.room_id,
|
||||||
|
result['response']
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
match = botlib.MessageMatch(room, message, bot, PREFIX)
|
||||||
|
#print(f"{message.sender} : {message.body}")
|
||||||
|
if match.is_not_from_this_bot() and match.prefix() and match.command(
|
||||||
|
"faq"):
|
||||||
|
await bot.api.send_markdown_message(
|
||||||
|
room.room_id,
|
||||||
|
load_faq())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@bot.listener.on_custom_event(nio.InviteMemberEvent)
|
@bot.listener.on_custom_event(nio.InviteMemberEvent)
|
||||||
async def example(room, event):
|
async def example(room, event):
|
||||||
if event.membership == "join":
|
if event.membership == "join":
|
||||||
await bot.api.send_markdown_message(
|
await bot.api.send_markdown_message(
|
||||||
room.room_id,
|
room.room_id,
|
||||||
commands.get_faq_string()
|
load_faq()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_questions():
|
||||||
|
return json.loads(open('data.json').read())["faq"]["questions"]
|
||||||
|
|
||||||
|
|
||||||
|
@bot.listener.on_message_event
|
||||||
|
async def faqresponse(room, message):
|
||||||
|
match = botlib.MessageMatch(room, message, bot, PREFIX)
|
||||||
|
if match.is_not_from_this_bot():
|
||||||
|
response = ""
|
||||||
|
questions = get_questions()
|
||||||
|
for q in questions:
|
||||||
|
if sum([ 1 for kp in q["key_phrases"] if kp in message.body]) == len(q["key_phrases"]):
|
||||||
|
response += q["question"] + "\n" + q["answer"]+"\n"
|
||||||
|
if response != "":
|
||||||
|
await bot.api.send_markdown_message(
|
||||||
|
room.room_id,
|
||||||
|
response + dfaq["footer"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bot.run()
|
bot.run()
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.1 MiB |
Loading…
Reference in a new issue