😝Part_ONE 总体设计
1.1 开发环境
-
编译器:
PyCharm Community Edition 2022.2.3
-
Python
版本:3.9.13
-
借用
go-cqhttp
框架:下载网址:https://github.com/Mrs4s/go-cqhttp/releases,选择windows
版本进行下载,配置好QQ
账号和http、post
处的地址设置【要与代码中的地址保持一致性】
1.2 需求分析
- 天气查询
- 心灵鸡汤
- 每日笑话
- 星座配对
- 生日花语
- 课表推送【只针对
HNUST
教务网导出的课表】 - 。。。。等的推送与实时查询
通过
go-cqhttp
框架,采用flask
轻量级服务器,编写一款能实现在后端登录一个机器人
1.3 参考资料
-
go-cqhttp
: go-cqhttp 帮助中心 -
专业实况天气接口:实况天气接口
-
实时降水, 降雨量接口:实时降水降雨
-
聚合数据:获取各种
API
【聚合数据】 -
表情
CQ
码ID
表:CQ码
1.4 设计流程
- 需求分析
- 确定框架
- 资源准备
- 代码敲定
- 调试代码
- 总结分析
😝Part_TWO 详细模块设计
2.1 server.py
:核心模块
作为项目的中枢,用于接收客户端发送的请求,并对其处理,将后端处理的结果返还给客户端。
一个人工智能–交互式闲聊对话
# 基于PLATO-MINI,模型在十亿级别的中文对话数据上进行了预训练,闲聊场景对话效果显著。
# 调用Taskflow工具集,智能对原始信息进行回复
dialogue = Taskflow("dialogue")
# 通过PaddleNLP中的Taskflow工具集,智能对原始信息进行回复,join函数用于去除方括号[]
s_message = " ".join(dialogue([raw_message]))
1. 私聊消息;2. 群聊消息;3. 智能回复
app = Flask(__name__) # 监听端口,获取QQ信息
@app.route('/', methods=["POST"]) # 路由
def post_data():
"""下面的request.get_json().get......是用来获取关键字的值用的,关键字参考上面代码段的数据格式"""
if request.get_json().get('message_type') == 'private': # 如果是私聊信息
user_id = request.get_json().get('sender').get('user_id') # 获取信息发送者的 QQ号码
raw_message = request.get_json().get('raw_message') # 获取原始信息
s_message = select_function(raw_message)
if len(s_message) != 0:
send_private_msg(user_id, s_message)
if request.get_json().get('message_type') == 'group': # 如果是群聊信息
group_id = request.get_json().get('group_id') # 获取群号
raw_message = request.get_json().get('raw_message') # 获取原始信息
if '[CQ:at,qq=xxxx]' in raw_message: # 如果@机器人则智能回复
# 通过PaddleNLP中的Taskflow工具集,智能对原始信息进行回复,join函数用于去除方括号[]
s_message = " ".join(dialogue([raw_message]))
else:
s_message = select_function(raw_message)
if len(s_message) != 0:
send_group_msg(group_id, s_message)
return 'OK'
主入口
def main():
t = threading.Thread(target=get_current_time)
t.start()
app.run(debug=True, host='127.0.0.1', port=5000) # 此处的 host和 port对应上面 yml文件的设置
if __name__ == '__main__':
main()
2.2 send_message
模块
主要分为俩个模块:
- 对传入的消息进行功能的选择,获取到相应的数据
- 发送消息的模块:私人消息和群消息,根据传入的信息将数据传给用户
2.2.1 select_function.py
:功能选择
人为设置对消息的处理,并获取相应的结果
def select_function(raw_message):
s_message = ""
if raw_message == "帮助" or raw_message == "help":
s_message = get_help_message()
elif raw_message == "天气查询" or raw_message == "天气" or raw_message == "tianqi" or raw_message == "tian qi" or raw_message == "weather":
s_message = get_the_weather()
elif raw_message[0:2] == "课表":
s_message = send_class_table(raw_message)
elif raw_message == '鸡汤' or raw_message == 'ChickenSoup':
s_message = get_chicken_soup()
elif raw_message == '笑话' or raw_message == 'joke':
s_message = get_joke()
elif raw_message == 'setu':
s_message = get_setu()
elif raw_message == '视频' or raw_message == '播放视频':
s_message = get_video()
elif raw_message[0:4] == '星座匹配':
s_message = get_ConstellationPairing(raw_message)
elif raw_message[0:4] == '生日花语':
s_message = get_birthdayFlower(raw_message)
return s_message
告知用户我们的功能有哪些
def get_help_message():
help_message = "可根据所需功能,输入相应字段得到想到结果\n" \
"功能(1):查询今日天气\n" \
"天气查询 | 天气 | tianqi | tian qi | weather\n" \
"功能(2):查询近三天的课表\n" \
"课表 + 今天or明天or后天 + 班级\n" \
"例:课表 后天 19物一 \n" \
"功能(3):享受每日鸡汤\n" \
"鸡汤 | ChickenSoup \n" \
"功能(4):享受每日笑话\n" \
"笑话 | joke \n" \
"功能(5):随机setu\n" \
"setu \n" \
"功能(6):播放视频\n" \
"视频 | 播放视频 \n" \
"功能(7):查询生日花语\n" \
"生日花语 YYYY-MM-DD \n" \
"功能(8):星座匹配结果\n" \
"星座匹配 男生星座 女生星座\n" \
"例:星座匹配 双子 金牛 \n" \
"其他情况下@机器人会智能回复喔"
return help_message
2.2.2 send_message.py
:传送消息
传送私人消息
def send_private_msg(user_id, message):
send_private_msg_url = 'http://127.0.0.1:10087/send_private_msg'
params = {
'user_id': user_id,
'message': message,
}
requests.get(send_private_msg_url, params).json()
传送群聊消息
def send_group_msg(group_id, message):
send_group_msg_url = 'http://127.0.0.1:10087/send_group_msg'
params = {
'group_id': group_id,
'message': message,
}
requests.get(send_group_msg_url, params).json()
2.3 API
模块
2.3.1 weather_query.py
:天气查询
接口:
https://v0.yiketianqi.com/api
,再人为获取我们需要的内容,此处用的是专业实况天气接口v62和 实时降水, 降雨量接口,此处只展示部分代码,读者可根据自身需求定义
def get_the_weather():
weather_url = 'https://v0.yiketianqi.com/api'
params_v62 = {
'appid': " ", # 自己获取
'appsecret': " ", # 自己获
'version': "v62",
'city': "湘潭",
'unescape': "1", # json不被unicode, 直接输出中文
}
weather_v62_res = requests.get(weather_url, params_v62).json()
week = weather_v62_res["week"]
city = weather_v62_res["city"]
tem = weather_v62_res["hours"][0]["tem"]
wea = weather_v62_res["hours"][0]["wea"]
aqi = weather_v62_res["hours"][0]["aqi"]
aqinum = weather_v62_res["hours"][0]["aqinum"]
tem1 = weather_v62_res["tem1"]
tem2 = weather_v62_res["tem2"]
win = weather_v62_res["hours"][0]["win"]
s_message = f'{city}\n' \
f'{time},{week}\n' \
f'气温{tem}度,{wea}\n' \
f'{msg}\n' \
f'最高温度:{tem1}度,最低温度:{tem2}度\n' \
f'空气质量:{aqi},指数:{aqinum}\n' \
f'{win},风力{win_speed}\n' \
f'湿度:{humidity},能见度:{visibility}\n' \
f'气压:{pressure}\n\n' \
f'消息更新时间:\n' \
f'{update_time}'
return s_message
2.3.2 curriculum.py
:课表查询
用于获取课表信息,定义一个课程类,获取每一节课的课程名、时间和地点,此处用到了正则表达式的相关内容,需要对课表进行解析,获取我们需要的内容。【只针对从
HNUST
教务处导出的课表】
课程类
class Curriculum:
# 星期几对应excel表中的哪一列
week_to_char = {
'星期一': 'B',
'星期二': 'C',
'星期三': 'D',
'星期四': 'E',
'星期五': 'F',
'星期六': 'G',
'星期日': 'H'
}
# 把excel中的行转换为对应的上课时间
row_to_jie = {
4: '时间:08:00-09:40',
5: '时间:10:00-11:40',
6: '时间:14:00-15:40',
7: '时间:16:00-17:40',
8: '时间:19:00-20:40'
}
def __init__(self, class_time, name, class_classroom):
self.class_time = class_time # 上课时间
self.name = name # 课程名称
self.class_classroom = class_classroom # 上课地点
# 输入参数,schedule: 第几周, week: 星期几, day: 几月几日
# which_day: 今天、明天、后天
# class_tag: 19物一
@classmethod
def excel_to_print(cls, which_day, class_tag, schedule, week, day):
"""
第二步: 从文件中读取课表
"""
# print(f'../static/{class_tag}.xlsx')
wb = load_workbook(f'static/{class_tag}.xlsx') # 读取excel档案
ws = wb.active # 打开预设的工作表,等价于 -> ws = wb['Sheet1']
class_num = 0 # 用来统计今天的课程数
curriculum_list = [] # 用来储存curriculum对象
for row in range(4, 8 + 1): # 读取第4行到第8行,即第一二节、第三四节、第五六节、第七八节、第九十节
char = Curriculum.week_to_char[week] # 读取第char列的数据
my_class = ws[char + str(row)].value # 按char列读取当天的课表
# print(my_class)
# print("----")
if my_class is not None:
start_week = int("".join(re.findall(r"\n(\d+)", my_class))) # 用正则表达式匹配课程的起始周, 4-15([周]), 4前面是换行\n,4后面是-
end_week = int("".join(re.findall(r"(\d+)\(", my_class))) # 用正则表达式匹配课程的结束周, 4-15([周]), 15前面是-, 15后面是(
if start_week <= schedule <= end_week: # 如果说当前schedule处在课程教学周,代表今天有这节课
class_num = class_num + 1
class_name = "".join(re.findall(r"^(.*)", my_class))
classroom = "".join(re.findall(r"]\n(.*)$", my_class))
curriculum_list.append(
Curriculum(Curriculum.row_to_jie[row], class_name, classroom)) # 加入到今天的课程list中
class_table_msg = ""
if class_num != 0:
class_table_msg = class_table_msg + f"{class_tag}的同学们,你们{which_day}有{class_num}节课:\n\n" \
"课表信息:\n"
for class_info in curriculum_list:
class_table_msg = class_table_msg + f"{class_info.name}\n" \
f"{class_info.class_time}\n" \
f"地点:{class_info.class_classroom}\n\n"
class_table_msg = class_table_msg + f"上课日期:\n" \
f"第{schedule}周 {week}({day.strftime('%m月%d日')})"
else:
class_table_msg = class_table_msg + f'{which_day}没课,好好happy吧!'
return class_table_msg
发送课表消息
定义第一周的第一天的日期,获取日期,计算当前是第几周星期几,发送课表信息
def send_class_table(raw_message):
week_list = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
first_date = date(2022, 9, 5) # 新学期第一周的第一天
try:
which_day = raw_message.split(' ')[1]
if which_day == "今天":
search_date = date.today() # 获取今天的日期
elif which_day == "明天":
search_date = (date.today() + timedelta(days=1)) # 获取明天的日期
elif which_day == "后天":
search_date = (date.today() + timedelta(days=2)) # 获取后天的日期
search_in_schedule = ((search_date - first_date).days // 7) + 1 # 计算处在第几周
# 格式化日期:strftime('%w'), %w 星期, 0-6 (0是星期天)
search_week = week_list[int(search_date.strftime('%w'))] # 计算处在星期几
class_table_msg = "【课表提醒】\n" + Curriculum.excel_to_print(which_day, raw_message.split(' ')[2], search_in_schedule,search_week, search_date)
except FileNotFoundError as fe:
return f"{raw_message.split(' ')[2]} 的课表目前还没有收录到数据库"
except Exception as e:
return "输入格式有误\n" \
"例:课表 后天 21数二 \n"
else:
return class_table_msg
2.3.3 juhe_api.py
:其他功能
从聚合数据上申请的
API
接口,此处只展示一个功能的代码,其他功能类似,可根据自身需求进行修改即可
心灵鸡汤
# 每日心灵鸡汤语录, API地址: https://www.juhe.cn/docs/api/id/669
def get_chicken_soup():
chicken_soup_url = 'https://apis.juhe.cn/fapig/soup/query' # 聚合数据,API地址
params = {
'key': "xx", # 聚合数据上获取即可
}
try:
chicken_soup_res = requests.get(chicken_soup_url, params).json()
chicken_soup_text = chicken_soup_res['result']['text']
chicken_soup_msg = f"今日鸡汤:\n" \
f"[CQ:face,id=171]{chicken_soup_text}"
except Exception as e:
return "今天的查询次数超过上限啦,明天再来看看吧!"
else:
return chicken_soup_msg
发送视频
def get_video():
video_url = 'http://106.52.78.177/wp-content/uploads/2022/10/1.mp4'
video_msg = f"[CQ:video,file={video_url}]"
return video_msg
备注:此处用到了
CQ
码,可以直接查询对应需求的标准就可【开头已附链接】
2.3.4 get_current_time.py
:获取当前时间
此处设置的是一个自动发送消息的接口,将程序挂在服务器上,此处设置的是早上八点发送当天的天气情况,晚上9点发送明天的课表情况,读者可根据实际需求自定义,只需获取一下当前时间即可。
now_time = datetime.datetime.now().strftime('%H:%M:%S') # 获取当前时间
2.4 static
模块
- 存放
resource
文件,此项目用于存放课表文件
😝 Part_THREE 效果展示
3.1 go-cqhttp
框架
3.2 Pycharm
端
3.3 功能帮助
3.4 天气查询
3.5 课表查询
3.6 心灵鸡汤
3.7 每日笑话
3.8 生日花语
3.9 星座匹配
3.10 视频播放
3.11 智能回复
😝 Part-FOUR 总结和体会
1. 学习到了什么?
- Python Flask 的基本框架
- 正则表达式的应用 – 课表解析
JSON
的基本使用API
获取- 交互式闲聊对话 —
PaddleNLP
- 如何模块化代码
2. 体会
- 加强专业知识的学习
- 提高自身的代码能力
- 不懂的问题多请教
- 实践出真知
3. 致谢
感谢
Chaotian Song
和OneWan
在学习此项目期间的帮助!