qqbot聊天机器人-会议室的预订

github:
https://github.com/cuihee/qqbot-meeting
可能有代码少许不一样
xl.py
from meeting_tools import *
# ==========================注意=============================
watch_group_name = ["0.0", 'SIPPR 智能与信息12楼', '智能与信息工程中心']
excel_file_name = "testMeeting.xlsx" # 新建的sheet第一天不太对,但是不影响使用
cmd_list = ['效率助手下载地址', '查询今天会议室预订情况', '查询明天会议室预订情况', 'help', # 0 1 2 3
'顺丰的联系方式', 'stop', 'watch_group_name']
# 关键词和触发的行为
cmd_dic = {
'效率助手下载地址': '',
'查询今天会议室预订情况': '',
'查询明天会议室预订情况': '',
'help': '',
'顺丰的联系方式': '',
'stop': '',
'watch_group_name': ''
}
def onQQMessage(bot, contact, member, content):
# 避免机器人自嗨 机器人发言请注意加上这个字符串
if '机器人回复' in content:
return
# 监视制定的群
if not my_watch_group(contact=contact, group_name=watch_group_name):
return
# todo 用dic替换list
for k, v in cmd_dic.items():
if k in content:
if isinstance(cmd_dic[k], type(func())):
# 是函数 就执行函数
pass
else:
# 不是函数 直接输出
pass
# return
if cmd_list[0] in content:
bot.SendTo(contact, "机器人回复 eepm.sippr.cn ")
return
if cmd_list[1] in content:
report_info = ask_info(excel_file_name, (datetime.date.today() + datetime.timedelta(days=0)).__str__())
bot.SendTo(contact, '机器人回复 \n'+'\n'.join(report_info))
return # 避免对查询语句进行预定会议室
if cmd_list[2] in content:
report_info = ask_info(excel_file_name, (datetime.date.today()+datetime.timedelta(days=1)).__str__())
bot.SendTo(contact, '机器人回复 \n'+'\n'.join(report_info))
return # 避免对查询语句进行预定会议室
if '[@ME]' in content and cmd_list[3] in content:
bot.SendTo(contact, '机器人回复 下列引号内的命令采用精确匹配。' + cmd_list.__str__())
return
if cmd_list[4] in content:
bot.SendTo(contact, '机器人回复 顺丰 15936240735')
return
if '[@ME]' in content and cmd_list[5] in content:
bot.SendTo(contact, '机器人回复 已停止')
# bot.Stop()
bot.Unplug('xl')
return
if '[@ME]' in content[:5]:
bot.SendTo(contact, "机器人回复 只要你at我,我就回复这一句\n用来查看插件是否启用中")
return
if cmd_list[6] in content:
bot.SendTo(contact, "机器人回复 "+watch_group_name.__str__())
return
dialog = dialog_clearify(content)
dialog = is_cmd(dialog)
if len(dialog) < 1:
print("不是预定会议室的语句")
return
else:
yuding_info = member.name + ' 群"' + contact.nick + '" ' + datetime.datetime.today().__str__()[:-7] \
+ ' '
book_ornot = find_yuding(dialog) # True False
riqi = find_riqi(dialog) # 2018-03-13
# print("获取日期:", riqi)
start_time, end_time = find_shijian(dialog) # 8:00, 9:15
# print("获取时间:", start_time, end_time)
fangjian = find_fangjian(dialog) # 12楼小会议室
# print("获取房间名:", get_meetingrooms_names()[fangjian])
yuding_info = yuding_info + riqi + ' '
yuding_info = yuding_info + get_meetingrooms_names()[fangjian] + ' '
yuding_info = yuding_info + start_time + '-' + end_time + ' '
print(yuding_info)
# 表格文件对象
excel_file = get_excel_file(filename=excel_file_name)
# print("获取文件:", excel_file)
excel_sheet = get_excel_sheet(riqi=riqi, file=excel_file)
# print("获取sheet:", excel_sheet)
column0 = 2 # 第一列是时间 从第二列开始是会议室编号 12层小会议室0 12层大会议室1 13层会议室2
excel_column = fangjian + column0
# print("获取列:", excel_column)
excel_date_row = get_excel_row(sheet=excel_sheet, today=riqi) # 下一行是8:00:00
# print("获取行:", excel_date_row)
delta_row_start, delta_row_end = get_dtime(start_time, end_time)
# print("获取行区段:", excel_date_row+delta_row_start, excel_date_row+delta_row_end)
# ==============================================注意=======================================================
# 不管从哪个群里获取的预订信息都反馈到0.0群里面!!!!!!!!!!!!!!!!
bl = bot.List('group', '0.0')
b = None
if bl:
b = bl[0]
# bot.SendTo(b, 'test')
deal_book(sheet=excel_sheet, start=excel_date_row + delta_row_start,
end=excel_date_row + delta_row_end, column=excel_column,
info=yuding_info, book=book_ornot, bot=bot, contact=b, # 注意这里的 contact !!!!!!!!!!!!!!!!!!!!!
member=member)
# 存储表格文件
excel_file.save(filename=excel_file_name)
print("\n")
def onPlug(bot):
s = bot.Plugins()
if 'xl_sitter' in s:
pass
else:
bot.Plug('xl_sitter')
def func():
pass
meeting_tools.py
"""
这个文件应该放在全局可以import的位置供xl.py调用
比如说现在我的D:/anaconda/Lib
(xl.py按照要求放在了C:/Users/c2534/.qqbot-tmp/plugins)
有时候(脚本运行后修改这个文件)这个文件会不起作用,手动重启qqbot用命令 qq fresh-restart扫码
"""
import datetime
from openpyxl import load_workbook, Workbook
import os
import re
# todo 规范一下好
def botreply(bot, contact, member, s):
# if '机器人回复' 开头:
# return
# 判断contact还是member
# bot.SendTo(contact, "机器人回复 \n"+s)
pass
def ask_info(file, dates):
info = ['无记录']
# 打开这个文件
f = get_excel_file(file)
# 用dates[:7]找sheet
fsheet = get_excel_sheet(dates, f)
# 用dates找row
frow = -1
for i in range(1, fsheet.max_row+1):
if fsheet.cell(row=i, column=1).value == dates:
frow = i
break
if frow == -1:
return info
# 默认deltarow为
deltafrow = 52 # 8:00-20:45=12*4+4=52
for i in range(2, fsheet.max_column+1): # 列
for j in range(1+frow, deltafrow+1+frow): # 行
if fsheet.cell(row=j, column=i).value is None:
continue
if fsheet.cell(row=j, column=i).value not in info:
info.append(str(fsheet.cell(row=j, column=i).value))
# 关闭文件
f.close()
if len(info) > 1:
info[:] = info[1:] # 删除第一个元素
return info
def my_watch_group(contact, group_name):
return contact.nick in group_name
# todo 考虑使用redis json存储规则
# 但因为是py脚本运行 随时可以修改代码 需求不强烈
def dialog_clearify(content):
"""
这里面的顺序不要乱
:param content:
:return:
"""
d = content
if not isinstance(d, type("字符串类型")):
return ""
clearify_dict = {'~~~': '-', "~~": "-", ' ': ' ',
'~~': '-', '~': '-', '---': '-',
'--': '-', '——': '-', ':': ':',
'~': '-',
'全天': '8:30-18:00',
'12楼': '12层', '13楼': '13层', '十三楼': '13层', '十二楼': '12层',
'今日': '今天', '明日': '明天',
'合昌': '和昌', '合唱': '和昌', '和唱': '和昌',
'点半': ':30', '点30': ':30', '点三十': ':30',
'点': ':00',
'十一': '11', '十二': '12', '十三': '13',
'十四': '14', '十五': '15', '十六': '16',
'十七': '17', '十八': '18', '十九': '19',
'二十': '20', '十': '10',
'九': '9', '八': '8', '七': '7',
'六': '6', '五': '5', '四': '4',
'三': '3', '二': '2', '一': '1',
'下午8:': '20:',
'预订': '预定',
'到': '-',
'(': '(', ')': ')',
',': '.', ',': '.', '。': '.'
}
for (k, v) in clearify_dict.items():
d = d.replace(k, v)
# 5:30-6:00 转换成 17:30-18:00
r1 = re.findall(r'([^0-9:-]?)([1-7])(:[0-9]{2,3}-)([2-8])(:[0-9]{2,3})', d)
if len(r1) >= 1:
d = re.subn(r'([^0-9:-]?)([1-7])(:[0-9]{2,3}-)([2-8])(:[0-9]{2,3})',
r1[0][0] + str(int(r1[0][1]) + 12) + r1[0][2] + str(int(r1[0][3]) + 12) + r1[0][4],
d)[0]
r1 = re.findall(r'([^0-9:])([0-9]{1,3})(-[0-9]{1,3}:[0-9]{2,3})', d)
if len(r1) >= 1:
d = re.subn(r'([^0-9:])([0-9]{1,3})(-[0-9]{1,3}:[0-9]{2,3})', r1[0][0] + r1[0][1] + ':00' + r1[0][2], d)[0]
return d
def is_cmd(dialog):
if not isinstance(dialog, type("")):
return ''
if "会议室" in dialog:
if "预" in dialog or "订" in dialog or "定" in dialog:
return dialog
return ''
def get_meetingrooms_names():
return ['小会议室', '大会议室', '13层会议室', '【会议室名称不详】无法正确记录']
def find_fangjian(dialog):
"""
用正则表达式从dialog中取出定义好的会议室名称
http://www.runoob.com/regexp/regexp-metachar.html
正则表达式教程↑
:param dialog: 传入的字符串
:return: 传出会议室序号
"""
huiyishi = get_meetingrooms_names()
meeting_room = '12层大会议室'
r1 = re.findall(r'([1][23]层)', dialog)
r2 = re.findall(r'([大小]?会议室)', dialog)
if r1.__len__() > 0:
if r1[0] == '13层': # 当前情况下13层只有一个会议室2
return 2
meeting_room = r1[0] + meeting_room[3:]
if r2.__len__() > 0:
meeting_room = meeting_room[:3] + r2[0]
for i in range(len(huiyishi)):
if meeting_room.find(huiyishi[i]) > -1:
return i # 0 1 2
return len(huiyishi)-1 # 3
def find_shijian(dialog):
st = '8:30'
et = '18:00'
r1 = re.findall(r'([0-9]?[0-9])[:点:]([0-5][0-9])', dialog)
if r1.__len__() >= 1: # 至少有一个时间
st = r1[0][0] + ':' + shijian_fenzhong_round(r1[0][1])
if r1.__len__() >= 2: # 有两个时间
et = shijian_round2(r1[1][0] + ':' + r1[1][1])
if r1.__len__() <= 0:
if dialog.find('上午') > -1:
st, et = '8:30', '12:00'
if dialog.find('下午') > -1:
st, et = '14:00', '18:00'
# 安全检查是否在早8:00-20:30之间
if int(st[:st.find(':')]) < 8:
st = '8' + st[st.find(':'):]
if int(st[:st.find(':')]) > 20:
st = '20' + st[st.find(':'):]
if int(et[:et.find(':')]) < 8:
et = '8' + et[et.find(':'):]
if int(et[:et.find(':')]) > 20:
et = '20' + et[et.find(':'):]
return st, et
def shijian_fenzhong_round(s):
if int(s) < 15:
return '00'
if int(s) < 30:
return '15'
if int(s) < 45:
return '30'
if int(s) < 60:
return '45'
return '45'
def shijian_round2(s):
if int(s[-2:]) > 45:
return str(int(s[:s.find(':')])+1) + ':00'
if int(s[-2:]) > 30:
return s[:s.find(':')] + ':45'
if int(s[-2:]) > 15:
return s[:s.find(':')] + ':30'
if int(s[-2:]) > 0:
return s[:s.find(':')] + ':15'
if int(s[-2:]) == 0:
return s
return s
def find_yuding(dialog):
return not ("取消" in dialog)
def find_riqi(dialog):
"""
:param dialog: 4.2
:return: 2018-04-02
"""
findre = re.findall(r'([12]?[0-9])[月.]([0-3]?[0-9])[日号]?', dialog) # 12月02日 10.3
if len(findre) == 1:
if len(findre[0][0]) == 1:
a = '0' + findre[0][0]
else:
a = findre[0][0]
if len(findre[0][1]) == 1:
b = '0' + findre[0][1]
else:
b = findre[0][1]
return datetime.date.today().__str__()[:5] + a + '-' + b # 2018-12-02
findre = re.findall(r'([0-3]?[0-9])[日号]', dialog) # 2号
if len(findre) == 1:
if len(findre[0]) == 1:
a = '0' + findre[0]
else:
a = findre[0]
return datetime.date.today().__str__()[:8] + a # 2018-12-02
if -1 < dialog.find("今"):
return datetime.date.today().__str__()
elif -1 < dialog.find("明"):
return (datetime.date.today() + datetime.timedelta(days=1)).__str__()
elif -1 < dialog.find("后"):
return (datetime.date.today() + datetime.timedelta(days=2)).__str__()
return datetime.date.today().__str__()
def get_excel_row(sheet, today):
"""
:param sheet:
:param today: datetime.date.today().__str__()
:return: row of today 只有日期没时间的那一行
"""
find_ornot = False
find_row = 0
for i in range(1, sheet.max_row+1):
if sheet.cell(row=i, column=1).value == today:
find_ornot = True
find_row = i
break
if find_ornot:
writetime(sheet=sheet, startrow=find_row + 1)
return find_row
else:
find_row = sheet.max_row + 1
sheet.cell(row=find_row, column=1).value = today
writetime(sheet=sheet, startrow=find_row + 1)
return find_row
def writetime(sheet, startrow):
"""
不包括today信息的一天时间
:param sheet:
:param startrow:
:return:
"""
m = ["00", "15", "30", "45"]
h = [i.__str__() for i in range(8, 21, 1)]
crow = startrow
for _h in h:
for _m in m:
sheet.cell(row=crow, column=1).value = _h + ":" + _m + ":00"
crow = crow + 1
def get_dtime(st, et):
"""
todo 感觉可以写成一个函数
计算所给时间段距离8:00的格子数 默认15min
请注意8:00是第一个格子
:param st: 时间 8:00
:param et: 时间 9:30
:return: 起始时间所在行是当天日期所在行+ds
"""
a = int(st[:st.find(":")])
b = int(st[st.find(":") + 1:])
c = int(et[:et.find(":")])
d = int(et[et.find(":") + 1:])
ds = (a - 8) * 4 + b // 15 + 1
de = (c - 8) * 4 + d // 15 + 1
return ds, de
def get_excel_file(filename):
"""
:param filename: 文件名带后缀的
:return: 打开指定文件名的文件对象
"""
# 得到当前系统目录下的文件名列表
dir_files = os.listdir(os.getcwd())
# 当前路径下有filename文件
if filename in dir_files:
wb = load_workbook(filename)
else:
wb = Workbook()
wb.save(filename)
wb = load_workbook(filename)
return wb
def get_excel_sheet(riqi, file):
sheetnames = file.get_sheet_names() # 所有表名
month_name = riqi[:7] # 目标表名
if month_name in sheetnames: # 存在
return file.get_sheet_by_name(name=month_name)
else:
return create_sheet(month_name, file)
def create_sheet(sheetname, file):
"""
:param sheetname: string
:param file: excel文件对象
:return: sheet对象
"""
# 如果excel文件中有这个名字的sheet 就直接返回这个sheet对象
if sheetname in file.get_sheet_names():
return file.get_sheet_by_name(sheetname)
# 在excel文件中新建一个名为sheetname的sheet
file.create_sheet(sheetname)
sheet = file.get_sheet_by_name(sheetname)
# 左上角 A1 写入今天的日期
sheet.cell(row=1, column=1).value = datetime.date.today().__str__() # [:8]+"01"
# 写时间
writetime(sheet=sheet, startrow=2)
# 写会议室名字
meeting_roomnames = get_meetingrooms_names()
# for (i, n) in meeting_roomnames:
# sheet.cell(row=1, column=i).value = n
for i in range(len(meeting_roomnames)):
sheet.cell(row=1, column=i+2).value = meeting_roomnames[i]
return sheet
def deal_book(sheet, start, end, column, info, book, bot, contact, member):
if book:
# 预定命令
occupied, occupied_info = is_occupied(sheet, start, end, column) # 是否被占用 占用信息
if occupied:
# 如果占用
bot.SendTo(contact, "机器人回复 失败,因为\"" + occupied_info + "\"占用")
# print("您预定失败,因为\"" + occupied_info + "\"占用")
else:
# 没有占用
occupy_it(sheet, start, end, column, info)
bot.SendTo(contact, "机器人回复 成功\n"+" 记录的信息: "+member.name+" "+info[-32:])
# print("成功预定")
else:
# 取消预定
unoccupy_it(sheet, start, end, column)
bot.SendTo(contact, '机器人回复 '+str(info[:info.find(' 群"')]) + "取消成功")
# print("取消预定")
print('\n')
def is_occupied(sheet, start, end, column):
busy = False # 假设没占用
busy_info = ""
for i in range(start, end, 1):
if sheet.cell(row=i, column=column).value is not None:
busy_info = sheet.cell(row=i, column=column).value
busy = True
break
return busy, busy_info
def occupy_it(sheet, st, en, co, info="占用人信息"):
for i in range(st, en, 1):
sheet.cell(column=co, row=i).value = info
def unoccupy_it(sheet, st, en, co):
for i in range(st, en, 1):
sheet.cell(column=co, row=i).value = None
def excel_file_close(file, name):
file.save(filename=name)
def _test_dialog_clearify():
assert dialog_clearify('预定4月2日和昌12楼小会议室5:30-6:00') \
== '预定4月2日和昌12层小会议室17:30-18:00', '对话语句清理函数dialog_clearify有问题'
assert dialog_clearify('预定4月2日和昌12楼小会议室2:30-6:00') \
== '预定4月2日和昌12层小会议室14:30-18:00', '对话语句清理函数dialog_clearify有问题'
assert dialog_clearify('预定4月3日和昌12楼大会议室9:00-11:00') \
== '预定4月3日和昌12层大会议室9:00-11:00', '对话语句清理函数dialog_clearify有问题'
assert dialog_clearify('预定4月2日上午和昌12楼小会议室,9:00--11:30') \
== '预定4月2日上午和昌12层小会议室.9:00-11:30', '对话语句清理函数dialog_clearify有问题'
assert dialog_clearify('预定28日(今天)下午12楼大会议室,15:00到16:00') \
== '预定28日(今天)下午12层大会议室.15:00-16:00', '对话语句清理函数dialog_clearify有问题'
assert dialog_clearify('预定今天全天小会议室') \
== '预定今天8:30-18:00小会议室', '对话语句清理函数dialog_clearify有问题'
assert dialog_clearify('预定4月2日和昌13楼大会议室11:00-12:00') \
== '预定4月2日和昌13层大会议室11:00-12:00', '对话语句清理函数dialog_clearify有问题'
assert dialog_clearify('预定27号,下午14点30到17点,和昌12层大会议室') \
== '预定27号.下午14:30-17:00.和昌12层大会议室', '对话语句清理函数dialog_clearify有问题'
def _test_find_fangjian():
assert find_fangjian('预定4月2日和昌12层小会议室17:30-18:00') == 0, '寻找会议室编号函数find_fangjian有问题'
assert find_fangjian('预定4月3日和昌12层大会议室9:00-11:00') == 1, '寻找会议室编号函数find_fangjian有问题'
assert find_fangjian('预定4月2日和昌13层大会议室11:00-12:00') == 2, '寻找会议室编号函数find_fangjian有问题'
assert find_fangjian('预定4月2日和昌13层会议室11:00-12:00') == 2, '寻找会议室编号函数find_fangjian有问题'
assert find_fangjian('预定今天8:30-18:00小会议室') == 0, '寻找会议室编号函数find_fangjian有问题'
assert find_fangjian('预定今天8:30-18:00老楼会议室') == 3, '寻找会议室编号函数find_fangjian有问题'
def _test_find_shijian():
assert find_shijian('预定4月2日和昌12层小会议室17:30-18:00') == ('17:30', '18:00'), '寻找开始和结束时间函数find_shijian有问题'
assert find_shijian('预定4月2日和昌12层小会议室14:30-18:00') == ('14:30', '18:00'), '寻找开始和结束时间函数find_shijian有问题'
assert find_shijian('预定28日(今天)下午12层大会议室.15:00-16:00') == ('15:00', '16:00'), '寻找开始和结束时间函数find_shijian有问题'
assert find_shijian('预定今天8:30-18:00小会议室') == ('8:30', '18:00'), '寻找开始和结束时间函数find_shijian有问题'
assert find_shijian('预定上午大会议室') == ('8:30', '12:00'), '寻找开始和结束时间函数find_shijian有问题'
assert find_shijian('订小会议室 9:10-10:30') == ('9:00', '10:30'), '寻找开始和结束时间函数find_shijian有问题'
def _test_find_riqi():
assert find_riqi('预定4月2日和昌12层小会议室17:30-18:00') == '2018-04-02', '寻找日期函数find_riqi有问题'
assert find_riqi('预定今天8:30-18:00小会议室') == datetime.date.today().__str__(), '寻找日期函数find_riqi有问题'
assert find_riqi('预定30日下午12楼小会议室.14:00-16:00') == '2018-04-30', '寻找日期函数find_riqi有问题'
assert find_riqi('预定27号.下午14:30-17:00.和昌12层大会议室') == '2018-04-27', '寻找日期函数find_riqi有问题'
assert find_riqi('预订12楼大会议室,12点到14点')[:7] == datetime.date.today().__str__()[:7], '寻找日期函数find_riqi有问题'
if __name__ == '__main__':
_test_dialog_clearify()
_test_find_fangjian()
_test_find_shijian()
_test_find_riqi()
xl_sitter.py
from meeting_tools import *
import time
watch_group_name = ["0.0", '张志琳、刘文、李豪、', 'SIPPR 智能与信息12楼', '智能与信息工程中心']
def onQQMessage(bot, contact, member, content):
# 避免机器人自嗨 机器人发言请注意加上这个字符串
if '机器人回复' in content:
return
# 监视制定的群
if not my_watch_group(contact=contact, group_name=watch_group_name):
return
if '[@ME]' in content:
if 'start' in content:
bot.Plug('xl')
time.sleep(2)
s = bot.Plugins()
if 'xl' in s:
bot.SendTo(contact, '机器人回复 插件启动成功')
else:
bot.SendTo(contact, '机器人回复 插件启动失败')