【项目心得 の 二】在开发时如果有具体想法需提前和前端沟通,寻求方便的解决方案
结合Python flask 视频流返回问题 & RTSP断流问题解决理解项目业务逻辑
文章目录
业务场景
- 视频检测:基于图片,视频和在线摄像头的舱门检测,烟雾检测和人员检测
- 语音识别:语音合成,语音转写
Note:这5个功能相互独立。
1、在业务开发时如果有个人具体的想法,在开发之前需和前端沟通
-
假如是单个用户:步骤是先导入视频,执行舱门分析,舱门视频还没分析完,用户转头执行烟雾分析,此时需要先关闭掉前一个舱门分析的进程。
如果在前端不提醒用户的情况下,设计类图如下,思想是通过
frame_detect_handler
处理基于图片,视频和摄像头的检测,使用container_map
来对用户的camera
对象进行注册和删除操作。
在实现时发现python的单例模式不管用,所以建议在前端提醒用户是否关闭掉之前分析的进程。
-
经验:
-
在开发一个功能的时候,先考虑这个功能是否容易实现;如果较难实现,是否可以在前端上增加人机交互功能,来辅助后端实现。
-
在后端开发时,很容易对业务进行抽象化、进而选择适合的设计模式,对业务相同部分进行封装,但是有些时候是对业务理解不是很深刻,导致在抽象和封装时容易造成偏差,比如像上面一样:在前端上增加一个事件,在后端增加一个调用接口,就可以控制
camera
对象的关闭
-
2、python单例模式
在flask
的每个视图(manhole_view
,fire_view
,faceRecog_view
)中import
蓝图下的frameDetect_handler
,发现是同一个对象。参考python实现单例模式的几种方法实例详解
predict_manhole <app.blueprints.utils.frame_detect_handler.FrameDetectHandler object at 0x000002DE03482288>
predict_fire <app.blueprints.utils.frame_detect_handler.FrameDetectHandler object at 0x000002DE03482288>
face_recog <app.blueprints.utils.frame_detect_handler.FrameDetectHandler object at 0x000002DE03482288>
3、Flask灵活处理post接口(同时支持 formdata 和 json)
Note:flask
在处理post请求时,可以同时获取json
或者formdata
封装的参数
我在使用postman
进行接口测试时,习惯将参数封装到formdata
中,而实际情况下(和前端对接时),除了上传文件之外,传字符串参数还是用json
封装方便。
所以flask
在处理post请求时,为了让接口更加灵活,可以同时两种传参格式,flask
代码如下:
'''用户删除'''
@dataManageB.route('/delete_person', methods=['POST'])
def delete_person():
if (request.method == 'POST'):
...
# 封装有效属性
for key in person.keys():
if (request.form.get(key) != None):
person[key] = request.form.get(key)
else:
person[key] = request.json.get(key)
# 删除
...
return jsonify({'code': 200, 'msg': '操作成功', 'data': True})
else:
return jsonify({'code': 400, 'msg': '操作失败:请使用POST方法'})
4、基于docker容器的后端部署(分文件夹打包)
考虑到甲方爸爸的要求,为了让后端项目离线部署,项目打包大小又不能大于一个光盘的存储容量(4.3G左右),需要对docker打包的镜像进行压缩,目前又两种解决方法:
- 抛弃原有的anaconda镜像(解压后就3.27G),使用干净的ubuntu20.04镜像(解压后73MB),但是直接在ubuntu环境下安装python和pip,配置会很繁琐和复杂(安装g++,gcc环境,pandas使用时可能会报
_bz
模块没找到的问题,网上还是建议使用anaconda)- 使用基于anaconda的镜像进行打包,将里面大的文件夹(
du * -sh
查询当前目录下子文件夹大小)单独拷贝出来,加载容器时再导入(docker
容器其实就是一个完整的文件系统,对宿主机具有隔离性,因此可以将不必要的大文件导出来,重新加载时再导入容器内使用)。
对docker
容器(anaconda原镜像解压后就3.27G)进行单独打包会比较大,由于/opt/conda/lib
文件比较大(2.8G),这里将其导成压缩包并从容器内拷贝出来,再重启容器时需要将这个压缩包导入到原/opt/conda/lib
位置。
原打包文件大小:
导出压缩包后打包文件大小:
基于docker
容器的后端部署过程如下:
-
如果没有docker环境:
sudo apt-get install -y docker.io
-
假设当前
docker
容器名为ai_platform
-
加载容器快照,生成
ai_platform_deploy:v1
镜像:cat ai_platform_deploy.tar | docker import - ai_platform_deploy:v1
-
通过
ai_platform_deploy:v1
镜像实例化容器(此时实例化容器会报错,容器启动不了,需要将文件拷贝进容器内才可启动):sudo docker run -it --name="ai_platform" -p 5000:5000 ai_platform_deploy:v1 /bin/bash
-
实例化容器后,将原
lib
文件打入进容器内,再启动进入容器#解压tar tar -xvzf opt_conda_lib.tar /home/temp #拷贝到容器内 docker cp /home/temp/lib 容器id:/opt/conda/ docker start 容器id
-
进入容器(如果已经进入则无需使用该命令):
sudo docker exec -it ai_platform /bin/bash
-
启动虚拟环境:
conda activate ai_env
-
修改
server_config_withDB.yml
的ip,配置主机的ip
(已在home
目录下创建id_dataset
和buffers
两个文件夹)vim /home/ai_platform_v1.0_deploy/app/resources/server_config_withDB.yml
-
进入项目根目录:
cd /home/ai_platform_v1.0_deploy
-
运行项目并挂起:
先查看后台的运行情况,确保无误后再nohup
gunicorn -w 5 -b 0.0.0.0:5000 --certfile=client-1.local.crt --keyfile=client-1.local.key manage:app
-
后台运行项目:
nohup gunicorn -w 5 -b 0.0.0.0:5000 --certfile=client-1.local.crt --keyfile=client-1.local.key manage:app >> ai_platform.log 2>&1 &
-
根据项目根目录下的
ai_platform.log
,查看服务的运行状态:tail -10 ai_platform.log
-
使用
https://虚拟机ip:5000/xxx
对后端接口进行访问
-