AiController.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. @Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
  5. @software: PyCharm
  6. @Version: python3.6
  7. @MODIFY DECORD:ansjer dev
  8. """
  9. import base64
  10. import json
  11. import logging
  12. import os
  13. import time
  14. import apns2
  15. import boto3
  16. import jpush
  17. from boto3.session import Session
  18. from django.views.generic.base import View
  19. from pyfcm import FCMNotification
  20. from AnsjerPush.config import AI_IDENTIFICATION_TAGS_DICT, CONFIG_US, CONFIG_EUR
  21. from AnsjerPush.config import AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, APNS_MODE, APNS_CONFIG, BASE_DIR, \
  22. JPUSH_CONFIG, FCM_CONFIG
  23. from AnsjerPush.config import CONFIG_INFO
  24. from Model.models import UidPushModel, AiService, VodHlsTag, VodHlsTagType
  25. from Object import MergePic
  26. from Object.DynamodbObject import DynamodbObject
  27. from Object.ETkObject import ETkObject
  28. from Object.ResponseObject import ResponseObject
  29. from Object.TokenObject import TokenObject
  30. from Object.enums.MessageTypeEnum import MessageTypeEnum
  31. from Object.utils import LocalDateTimeUtil
  32. from Service.CommonService import CommonService
  33. from Service.EquipmentInfoService import EquipmentInfoService
  34. # AI服务
  35. class AiView(View):
  36. def get(self, request, *args, **kwargs):
  37. request.encoding = 'utf-8'
  38. operation = kwargs.get('operation')
  39. return self.validation(request.GET, request, operation)
  40. def post(self, request, *args, **kwargs):
  41. request.encoding = 'utf-8'
  42. operation = kwargs.get('operation')
  43. return self.validation(request.POST, request, operation)
  44. def validation(self, request_dict, request, operation):
  45. response = ResponseObject()
  46. if operation is None:
  47. return response.json(444, 'error path')
  48. elif operation == 'identification': # ai识别
  49. return self.do_ai_identification(request.POST, response)
  50. else:
  51. token = request_dict.get('token', None)
  52. # 设备主键uid
  53. tko = TokenObject(token)
  54. response.lang = tko.lang
  55. if tko.code != 0:
  56. return response.json(tko.code)
  57. userID = tko.userID
  58. if operation == 'identification': # ai识别
  59. return self.do_ai_identification(request_dict, response)
  60. else:
  61. return response.json(414)
  62. def do_ai_identification(self, request_dict, response):
  63. etk = request_dict.get('etk', None)
  64. n_time = request_dict.get('n_time', None)
  65. channel = request_dict.get('channel', '1')
  66. receiveTime = int(time.time())
  67. logger = logging.getLogger('info')
  68. logger.info('进入-----------into----ai--api')
  69. logger.info("etk={etk}".format(etk=etk))
  70. if not etk:
  71. return response.json(444)
  72. try:
  73. # 解密uid及判断长度
  74. eto = ETkObject(etk)
  75. uid = eto.uid
  76. logger.info("uid={uid}".format(uid=uid))
  77. if len(uid) != 20 and len(uid) != 14:
  78. return response.json(444)
  79. logger.info('uid={uid}'.format(uid=uid))
  80. logger.info('n_time={n_time}'.format(n_time=n_time))
  81. ##通过uid查出endTime是否过期,并且ai开关是否打开
  82. AiServiceQuery = AiService.objects.filter(uid=uid, detect_status=1, use_status=1, endTime__gt=receiveTime). \
  83. values('detect_group')
  84. if not AiServiceQuery.exists():
  85. logger.info('none-----aiService')
  86. return response.json(173)
  87. detect_group = AiServiceQuery[0]['detect_group']
  88. # {}??
  89. #
  90. file_post_one = request_dict.get('fileOne', None)
  91. file_post_two = request_dict.get('fileTwo', None)
  92. file_post_three = request_dict.get('fileThree', None)
  93. file_list = [file_post_one, file_post_two, file_post_three]
  94. del file_post_one, file_post_two, file_post_three
  95. if not all(file_list):
  96. for k, val in enumerate(file_list):
  97. if not val:
  98. return response.json(444, '缺少第{k}张图'.format(k=k + 1))
  99. dir_path = os.path.join(BASE_DIR, 'static/ai/' + uid + '/' + str(n_time))
  100. if not os.path.exists(dir_path):
  101. os.makedirs(dir_path)
  102. file_path_list = []
  103. for i, val in enumerate(file_list):
  104. val = val.replace(' ', '+')
  105. val = base64.b64decode(val)
  106. file_path = "{dir_path}/{n_time}_{i}.jpg".format(dir_path=dir_path, n_time=n_time, i=i)
  107. file_path_list.append(file_path)
  108. with open(file_path, 'wb') as f:
  109. f.write(val)
  110. f.close()
  111. image_size = 0 # 每张小图片的大小,等于0是按原图大小进行合并
  112. image_colnum = 1 # 合并成一张图后,一行有几个小图
  113. image_size = MergePic.merge_images(dir_path, image_size, image_colnum)
  114. photo = open(dir_path + '.jpg', 'rb') # 打开合成图
  115. # photo = open(r'E:\test---------------\test\snipaste20220121_215952.jpg', 'rb')
  116. # 识别合成图片
  117. maxLabels = 50 # 最大标签
  118. minConfidence = 80 # 置信度
  119. ai_start_time = int(time.time())
  120. client = boto3.client(
  121. 'rekognition',
  122. aws_access_key_id='AKIA2E67UIMD6JD6TN3J',
  123. aws_secret_access_key='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',
  124. region_name='us-east-1')
  125. # doc:
  126. rekognition_res = client.detect_labels(
  127. Image={'Bytes': photo.read()},
  128. MaxLabels=maxLabels,
  129. MinConfidence=minConfidence)
  130. photo.close()
  131. if rekognition_res['ResponseMetadata']['HTTPStatusCode'] != 200:
  132. return response.json(173)
  133. # rekognition_res = '{"Labels":[{"Name":"Person","Confidence":99.55254364013672,"Instances":[{"BoundingBox":{"Width":0.07776174694299698,"Height":0.13592061400413513,"Left":0.38370513916015625,"Top":0.09075711667537689},"Confidence":99.55254364013672},{"BoundingBox":{"Width":0.10947742313146591,"Height":0.12066027522087097,"Left":0.2790755331516266,"Top":0.10242735594511032},"Confidence":99.54237365722656},{"BoundingBox":{"Width":0.2935298979282379,"Height":0.09244367480278015,"Left":0.6143953204154968,"Top":0.9052517414093018},"Confidence":98.82627868652344},{"BoundingBox":{"Width":0.35492533445358276,"Height":0.21574528515338898,"Left":0.3411630690097809,"Top":0.27151572704315186},"Confidence":96.74708557128906},{"BoundingBox":{"Width":0.39604419469833374,"Height":0.09648437798023224,"Left":0.060247838497161865,"Top":0.9000436663627625},"Confidence":95.03588104248047},{"BoundingBox":{"Width":0.1105344295501709,"Height":0.1257047802209854,"Left":0.0025259912945330143,"Top":0.8314586877822876},"Confidence":92.17312622070312},{"BoundingBox":{"Width":0.13166509568691254,"Height":0.12054375559091568,"Left":0.10105808824300766,"Top":0.8364697694778442},"Confidence":89.71287536621094},{"BoundingBox":{"Width":0.22752150893211365,"Height":0.09563954919576645,"Left":0.7430258989334106,"Top":0.8961490392684937},"Confidence":85.34542083740234},{"BoundingBox":{"Width":0.1297324150800705,"Height":0.096779465675354,"Left":0.4607183039188385,"Top":0.9025260806083679},"Confidence":83.4525375366211}],"Parents":[]},{"Name":"Human","Confidence":99.55254364013672,"Instances":[],"Parents":[]},{"Name":"Husky","Confidence":98.64888763427734,"Instances":[],"Parents":[{"Name":"Dog"},{"Name":"Pet"},{"Name":"Canine"},{"Name":"Animal"},{"Name":"Mammal"}]},{"Name":"Dog","Confidence":98.64888763427734,"Instances":[{"BoundingBox":{"Width":0.2157023847103119,"Height":0.2352331429719925,"Left":0.26413947343826294,"Top":0.5162186622619629},"Confidence":94.06558990478516},{"BoundingBox":{"Width":0.23323440551757812,"Height":0.2026243358850479,"Left":0.4748744070529938,"Top":0.5457579493522644},"Confidence":92.4560546875},{"BoundingBox":{"Width":0.31273096799850464,"Height":0.23413777351379395,"Left":0.6696768999099731,"Top":0.5142407417297363},"Confidence":91.39192199707031},{"BoundingBox":{"Width":0.27037277817726135,"Height":0.21958686411380768,"Left":0.053227268159389496,"Top":0.5305629968643188},"Confidence":90.0697250366211}],"Parents":[{"Name":"Pet"},{"Name":"Canine"},{"Name":"Animal"},{"Name":"Mammal"}]},{"Name":"Canine","Confidence":98.64888763427734,"Instances":[],"Parents":[{"Name":"Mammal"},{"Name":"Animal"}]},{"Name":"Pet","Confidence":98.64888763427734,"Instances":[],"Parents":[{"Name":"Animal"}]},{"Name":"Mammal","Confidence":98.64888763427734,"Instances":[],"Parents":[{"Name":"Animal"}]},{"Name":"Animal","Confidence":98.64888763427734,"Instances":[],"Parents":[]},{"Name":"Car","Confidence":96.32373809814453,"Instances":[{"BoundingBox":{"Width":0.5476366281509399,"Height":0.10842914879322052,"Left":0.38325461745262146,"Top":0.11447073519229889},"Confidence":96.32373809814453}],"Parents":[{"Name":"Vehicle"},{"Name":"Transportation"}]},{"Name":"Transportation","Confidence":96.32373809814453,"Instances":[],"Parents":[]},{"Name":"Vehicle","Confidence":96.32373809814453,"Instances":[],"Parents":[{"Name":"Transportation"}]},{"Name":"Automobile","Confidence":96.32373809814453,"Instances":[],"Parents":[{"Name":"Vehicle"},{"Name":"Transportation"}]},{"Name":"Clothing","Confidence":86.02703857421875,"Instances":[],"Parents":[]},{"Name":"Apparel","Confidence":86.02703857421875,"Instances":[],"Parents":[]},{"Name":"Puppy","Confidence":85.16007232666016,"Instances":[],"Parents":[{"Name":"Dog"},{"Name":"Pet"},{"Name":"Canine"},{"Name":"Animal"},{"Name":"Mammal"}]},{"Name":"Wheel","Confidence":74.5079116821289,"Instances":[{"BoundingBox":{"Width":0.0818198174238205,"Height":0.052956655621528625,"Left":0.4488227367401123,"Top":0.17395207285881042},"Confidence":74.5079116821289},{"BoundingBox":{"Width":0.09288611263036728,"Height":0.050751496106386185,"Left":0.7844013571739197,"Top":0.17587198317050934},"Confidence":51.4537353515625}],"Parents":[{"Name":"Machine"}]},{"Name":"Machine","Confidence":74.5079116821289,"Instances":[],"Parents":[]}],"LabelModelVersion":"2.0","ResponseMetadata":{"RequestId":"1088325e-996b-4982-9afb-bd95df6d6fb3","HTTPStatusCode":200,"HTTPHeaders":{"x-amzn-requestid":"1088325e-996b-4982-9afb-bd95df6d6fb3","content-type":"application/x-amz-json-1.1","content-length":"4291","date":"Tue, 15 Mar 2022 06:44:17 GMT"},"RetryAttempts":0}}'
  134. # rekognition_res = json.loads(rekognition_res)
  135. labels = self.labelsCoords(detect_group, rekognition_res, image_size) # 检查标签是否符合用户选择的识别类型
  136. logger.info('-----记录返回labels')
  137. logger.info('labels')
  138. # return response.json(0,labels)
  139. # 将识别结果存到S3以及DynamoDB
  140. AiView.store_image_results_to_dynamo_and_s3(file_path_list, uid, channel, n_time, labels, rekognition_res)
  141. if len(labels['label_list']) == 0:
  142. # 需要删除图片
  143. # photo.close()
  144. # self.del_path(os.path.join(BASE_DIR, 'static/ai/' + uid))
  145. logger.info('没有识别到任何标签-----------------')
  146. self.del_path(dir_path)
  147. self.del_path(dir_path + '.jpg')
  148. logger.info('删除图片成功,路径为:{}'.format(dir_path))
  149. return response.json(10055)
  150. eventType = labels['eventType']
  151. label_str = ','.join(labels['label_list'])
  152. new_bounding_box_dict = labels['new_bounding_box_dict']
  153. logger.info(eventType)
  154. logger.info(label_str)
  155. # 上传缩略图到s3
  156. file_dict = {}
  157. for i, val in enumerate(file_path_list):
  158. file_dict[val] = "{uid}/{channel}/{n_time}_{i}.jpeg".format(uid=uid, channel=channel, # 封面图
  159. n_time=n_time, i=i)
  160. self.upload_s3(file_dict, dir_path)
  161. # time.sleep(10)
  162. # 存储消息以及推送
  163. is_st = 3 # 多图
  164. # 查询推送数据
  165. uid_push_qs = UidPushModel.objects.filter(uid_set__uid=uid). \
  166. values('token_val', 'app_type', 'appBundleId', 'm_code', 'push_type', 'userID_id',
  167. 'userID__NickName',
  168. 'lang', 'm_code', 'tz', 'uid_set__nickname', 'uid_set__detect_interval',
  169. 'uid_set__detect_group',
  170. 'uid_set__channel')
  171. if not uid_push_qs.exists():
  172. return response.json(173)
  173. uid_push_list = []
  174. for qs in uid_push_qs:
  175. uid_push_list.append(qs)
  176. nickname = uid_push_list[0]['uid_set__nickname']
  177. if not nickname:
  178. nickname = uid
  179. eq_list = []
  180. userID_ids = []
  181. local_date_time = ''
  182. for up in uid_push_list:
  183. push_type = up['push_type']
  184. appBundleId = up['appBundleId']
  185. token_val = up['token_val']
  186. lang = up['lang']
  187. tz = up['tz']
  188. if tz is None or tz == '':
  189. tz = 0
  190. local_date_time = CommonService.get_now_time_str(n_time=n_time, tz=tz, lang='cn')
  191. logger.info('----AI消息存库{},{},{}'.format(uid, local_date_time, tz))
  192. local_date_time = local_date_time[0:10]
  193. # 以下是存库
  194. userID_id = up["userID_id"]
  195. if userID_id not in userID_ids:
  196. now_time = int(time.time())
  197. eq_list.append(EquipmentInfoService.get_equipment_info_obj(
  198. local_date_time,
  199. device_user_id=userID_id,
  200. event_time=n_time,
  201. event_type=eventType,
  202. device_uid=uid,
  203. device_nick_name=nickname,
  204. channel=channel,
  205. alarm='检查到{labels} \tChannel:{channel}'.format(labels=label_str, channel=channel),
  206. is_st=is_st,
  207. receive_time=receiveTime,
  208. add_time=now_time,
  209. storage_location=2,
  210. border_coords=json.dumps(new_bounding_box_dict)
  211. ))
  212. userID_ids.append(userID_id)
  213. # 推送标题
  214. msg_title = self.get_msg_title(appBundleId=appBundleId, nickname=nickname)
  215. # 推送内容
  216. msg_text = self.get_msg_text(channel=channel, n_time=n_time, lang=lang, tz=tz, label_list=label_str)
  217. kwargs = {
  218. 'uid': uid,
  219. 'channel': channel,
  220. 'event_type': eventType,
  221. 'n_time': n_time,
  222. 'appBundleId': appBundleId,
  223. 'token_val': token_val,
  224. 'msg_title': msg_title,
  225. 'msg_text': msg_text,
  226. }
  227. try:
  228. # 推送消息
  229. if push_type == 0: # ios apns
  230. self.do_apns(**kwargs)
  231. elif push_type == 1: # android gcm
  232. self.do_fcm(**kwargs)
  233. elif push_type == 2: # android jpush
  234. self.do_jpush(**kwargs)
  235. except Exception as e:
  236. logger.info(
  237. "errLine={errLine}, errMsg={errMsg}".format(errLine=e.__traceback__.tb_lineno, errMsg=repr(e)))
  238. continue
  239. week = LocalDateTimeUtil.date_to_week(local_date_time)
  240. # 分表批量存储
  241. if eq_list and len(eq_list) > 0:
  242. logger.info("AI存库中........")
  243. result = EquipmentInfoService.equipment_info_bulk_create(week, eq_list)
  244. logger.info("-.-存库结果{}".format(result))
  245. AiView.save_cloud_ai_tag(uid, int(n_time), eventType, week)
  246. return response.json(0)
  247. except Exception as e:
  248. print(e)
  249. data = {
  250. 'errLine': e.__traceback__.tb_lineno,
  251. 'errMsg': repr(e)
  252. }
  253. return response.json(48, data)
  254. def del_path(self, path):
  255. if not os.path.exists(path):
  256. return
  257. if os.path.isfile(path):
  258. os.remove(path)
  259. else:
  260. items = os.listdir(path)
  261. for f in items:
  262. c_path = os.path.join(path, f)
  263. if os.path.isdir(c_path):
  264. self.del_path(c_path)
  265. else:
  266. os.remove(c_path)
  267. os.rmdir(path)
  268. ## 检查是否有符合条件的标签,并且返回标签坐标位置信息
  269. def labelsCoords(self, user_detect_group, rekognition_res, image_size):
  270. logger = logging.getLogger('info')
  271. labels = rekognition_res['Labels']
  272. label_name = []
  273. label_list = []
  274. logger.info('--------识别到的标签-------')
  275. logger.info(labels)
  276. all_labels_type = {
  277. '1': ['Person', 'Human'], # 人
  278. '2': ['Pet', 'Dog', 'Canine', 'Animal', 'Puppy', 'Cat'], # 动物
  279. '3': ['Vehicle', 'Car', 'Transportation', 'Automobile', 'Bus'], # 车
  280. '4': ['Package', 'Carton', 'Cardboard', 'Package Delivery'] # 包裹
  281. }
  282. # 找出识别的所有标签
  283. for label in labels:
  284. label_name.append(label['Name'])
  285. for Parents in label['Parents']:
  286. label_name.append(Parents['Name'])
  287. logger.info('标签名------')
  288. logger.info(label_name)
  289. # 删除用户没有选择的ai识别类型, 并且得出最终识别结果
  290. user_detect_list = user_detect_group.split(',')
  291. user_detect_list = [i.strip() for i in user_detect_list]
  292. conform_label_list = []
  293. conform_user_d_group = set()
  294. for key, label_type_val in all_labels_type.items():
  295. if key in user_detect_list:
  296. for label in label_type_val:
  297. if label in label_name:
  298. conform_user_d_group.add(key)
  299. conform_label_list.append(label)
  300. # 找出标签边框线位置信息
  301. boundingBoxList = []
  302. for label in labels:
  303. if label['Name'] in conform_label_list:
  304. for boundingBox in label['Instances']:
  305. boundingBoxList.append(boundingBox['BoundingBox'])
  306. # 找出边框位置信息对应的单图位置并重新计算位置比
  307. merge_image_height = image_size['height']
  308. # merge_image_width = image_size['width']
  309. single_height = merge_image_height // image_size['num']
  310. new_bounding_box_dict = {}
  311. new_bounding_box_dict['file_0'] = []
  312. new_bounding_box_dict['file_1'] = []
  313. new_bounding_box_dict['file_2'] = []
  314. # new_bounding_box_dict['file_3'] = []
  315. for k, val in enumerate(boundingBoxList):
  316. boundingBoxTop = merge_image_height * val['Top']
  317. # 找出当前边框属于哪张图片范围
  318. boxDict = {}
  319. for i in range(image_size['num']):
  320. min = i * single_height # 第n张图
  321. max = (i + 1) * single_height
  322. if boundingBoxTop >= min and boundingBoxTop <= max:
  323. # print("属于第{i}张图".format(i=i+1))
  324. boxDict['Width'] = val['Width']
  325. boxDict['Height'] = merge_image_height * val['Height'] / single_height
  326. boxDict['Top'] = ((merge_image_height * val['Top']) - (
  327. i * single_height)) / single_height # 减去前i张图片的高度
  328. boxDict['Left'] = val['Left']
  329. new_bounding_box_dict["file_{i}".format(i=i)].append(boxDict)
  330. # exit(new_bounding_box_list)
  331. conform_user_d_group = list(conform_user_d_group)
  332. if len(conform_user_d_group) > 0:
  333. conform_user_d_group.sort()
  334. # 集成识别标签
  335. for label_key in conform_user_d_group:
  336. label_list.append(AI_IDENTIFICATION_TAGS_DICT[label_key])
  337. eventType = ''.join(conform_user_d_group) # 组合类型
  338. else:
  339. eventType = ''
  340. logger.info('------conform_user_d_group------ {}'.format(conform_user_d_group))
  341. logger.info('------label_list------ {}'.format(label_list))
  342. return {'eventType': eventType, 'label_list': label_list,
  343. 'new_bounding_box_dict': new_bounding_box_dict}
  344. def upload_s3(self, file_dict, dir_path):
  345. try:
  346. if CONFIG_INFO == CONFIG_US or CONFIG_INFO == CONFIG_EUR:
  347. # 存国外
  348. aws_key = AWS_ACCESS_KEY_ID[1]
  349. aws_secret = AWS_SECRET_ACCESS_KEY[1]
  350. session = Session(aws_access_key_id=aws_key,
  351. aws_secret_access_key=aws_secret,
  352. region_name="us-east-1")
  353. s3 = session.resource("s3")
  354. bucket = "foreignpush"
  355. else:
  356. # 存国内
  357. aws_key = AWS_ACCESS_KEY_ID[0]
  358. aws_secret = AWS_SECRET_ACCESS_KEY[0]
  359. session = Session(aws_access_key_id=aws_key,
  360. aws_secret_access_key=aws_secret,
  361. region_name="cn-northwest-1")
  362. s3 = session.resource("s3")
  363. bucket = "push"
  364. for file_path, upload_path in file_dict.items():
  365. print('-------')
  366. print(file_path)
  367. print('-------')
  368. upload_data = open(file_path, "rb")
  369. # upload_key = "test"
  370. s3.Bucket(bucket).put_object(Key=upload_path, Body=upload_data)
  371. # 需要删除图片
  372. logger = logging.getLogger('info')
  373. self.del_path(dir_path)
  374. self.del_path(dir_path + '.jpg')
  375. logger.info('删除图片成功,路径为:{}'.format(dir_path))
  376. return True
  377. except Exception as e:
  378. print(repr(e))
  379. return False
  380. def get_msg_title(self, appBundleId, nickname):
  381. package_title_config = {
  382. 'com.ansjer.customizedd_a': 'DVS',
  383. 'com.ansjer.zccloud_a': 'ZosiSmart',
  384. 'com.ansjer.zccloud_ab': '周视',
  385. 'com.ansjer.adcloud_a': 'ADCloud',
  386. 'com.ansjer.adcloud_ab': 'ADCloud',
  387. 'com.ansjer.accloud_a': 'ACCloud',
  388. 'com.ansjer.loocamccloud_a': 'Loocam',
  389. 'com.ansjer.loocamdcloud_a': 'Anlapus',
  390. 'com.ansjer.customizedb_a': 'COCOONHD',
  391. 'com.ansjer.customizeda_a': 'Guardian365',
  392. 'com.ansjer.customizedc_a': 'PatrolSecure',
  393. }
  394. if appBundleId in package_title_config.keys():
  395. return package_title_config[appBundleId] + '(' + nickname + ')'
  396. else:
  397. return nickname
  398. def get_msg_text(self, channel, n_time, lang, tz, label_list):
  399. n_date = CommonService.get_now_time_str(n_time=n_time, tz=tz, lang=lang)
  400. if lang == 'cn':
  401. msg = '摄像头AI识别到了{}'.format(label_list)
  402. send_text = '{msg} 通道:{channel} 日期:{date}'.format(msg=msg, channel=channel, date=n_date)
  403. else:
  404. msg = 'Camera AI recognizes {}'.format(label_list)
  405. send_text = '{msg} channel:{channel} date:{date}'.format(msg=msg, channel=channel, date=n_date)
  406. return send_text
  407. @classmethod
  408. def save_cloud_ai_tag(cls, uid, event_time, types, week):
  409. """
  410. 保存云存AI标签
  411. """
  412. try:
  413. types = str(types)
  414. if not types:
  415. return False
  416. n_time = int(time.time())
  417. vod_hls_tag = {"uid": uid, "ai_event_time": event_time, "created_time": n_time, 'tab_num': int(week)}
  418. vod_tag_vo = VodHlsTag.objects.create(**vod_hls_tag)
  419. tag_list = []
  420. if len(types) > 1:
  421. for i in range(1, len(types) + 1):
  422. ai_type = MessageTypeEnum(int(types[i - 1:i]))
  423. vod_tag_type_vo = VodHlsTagType(tag_id=vod_tag_vo.id, created_time=n_time, type=ai_type.value)
  424. tag_list.append(vod_tag_type_vo)
  425. else:
  426. ai_type = MessageTypeEnum(int(types))
  427. vod_tag_type_vo = {"tag_id": vod_tag_vo.id, "created_time": n_time, "type": ai_type.value}
  428. VodHlsTagType.objects.create(**vod_tag_type_vo)
  429. if tag_list:
  430. VodHlsTagType.objects.bulk_create(tag_list)
  431. return True
  432. except Exception as e:
  433. print('AI标签存储异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  434. return False
  435. def do_jpush(self, uid, channel, appBundleId, token_val, event_type, n_time, msg_title, msg_text):
  436. app_key = JPUSH_CONFIG[appBundleId]['Key']
  437. master_secret = JPUSH_CONFIG[appBundleId]['Secret']
  438. # 此处换成各自的app_key和master_secre
  439. _jpush = jpush.JPush(app_key, master_secret)
  440. push = _jpush.create_push()
  441. push.audience = jpush.registration_id(token_val)
  442. push_data = {"alert": "Motion ", "event_time": n_time, "event_type": event_type, "msg": "",
  443. "received_at": n_time, "sound": "sound.aif", "uid": uid, "zpush": "1", "channel": channel}
  444. android = jpush.android(alert=msg_text, priority=1, style=1, alert_type=7,
  445. big_text=msg_text, title=msg_title,
  446. extras=push_data)
  447. push.notification = jpush.notification(android=android)
  448. push.platform = jpush.all_
  449. res = push.send()
  450. print(res)
  451. return res.status_code
  452. def do_fcm(self, uid, channel, appBundleId, token_val, event_type, n_time, msg_title, msg_text):
  453. try:
  454. serverKey = FCM_CONFIG[appBundleId]
  455. push_service = FCMNotification(api_key=serverKey)
  456. data = {"alert": "Motion ", "event_time": n_time, "event_type": event_type, "msg": "",
  457. "received_at": n_time, "sound": "sound.aif", "uid": uid, "zpush": "1", "channel": channel}
  458. result = push_service.notify_single_device(registration_id=token_val, message_title=msg_title,
  459. message_body=msg_text, data_message=data,
  460. extra_kwargs={
  461. 'default_vibrate_timings': True,
  462. 'default_sound': True,
  463. 'default_light_settings': True
  464. })
  465. print('fcm push ing')
  466. print(result)
  467. return result
  468. except Exception as e:
  469. return 'serverKey abnormal'
  470. def do_apns(self, uid, channel, appBundleId, token_val, event_type, n_time, msg_title, msg_text):
  471. logger = logging.getLogger('info')
  472. logger.info("进来do_apns函数了")
  473. logger.info(token_val)
  474. logger.info(APNS_MODE)
  475. logger.info(os.path.join(BASE_DIR, APNS_CONFIG[appBundleId]['pem_path']))
  476. try:
  477. cli = apns2.APNSClient(mode=APNS_MODE,
  478. client_cert=os.path.join(BASE_DIR, APNS_CONFIG[appBundleId]['pem_path']))
  479. push_data = {"alert": "Motion ", "event_time": n_time, "event_type": event_type, "msg": "",
  480. "received_at": n_time, "sound": "", "uid": uid, "zpush": "1", "channel": channel}
  481. alert = apns2.PayloadAlert(body=msg_text, title=msg_title)
  482. payload = apns2.Payload(alert=alert, custom=push_data, sound="default")
  483. n = apns2.Notification(payload=payload, priority=apns2.PRIORITY_LOW)
  484. res = cli.push(n=n, device_token=token_val, topic=appBundleId)
  485. if res.status_code == 200:
  486. return res.status_code
  487. else:
  488. logger.info('apns push fail')
  489. logger.info(res.reason)
  490. return res.status_code
  491. except (ValueError, ArithmeticError):
  492. return 'The program has a numeric format exception, one of the arithmetic exceptions'
  493. except Exception as e:
  494. print(repr(e))
  495. logger.info(repr(e))
  496. return repr(e)
  497. @staticmethod
  498. def store_image_results_to_dynamo_and_s3(file_path_list, uid, channel, n_time, labels_data,
  499. reko_result):
  500. """
  501. 将图片识别结果存储到dynamoDB并且存储到S3
  502. @param file_path_list: 图片名称列表
  503. @param uid: 设备uid
  504. @param channel: 设备通道号
  505. @param n_time: 设备触发移动侦测时间戳
  506. @param labels_data: 标签数据(经过reko_result结果进行计算后的数据)
  507. @param reko_result: rekognition 响应结果
  508. @return: 保存结果
  509. """
  510. logger = logging.getLogger('info')
  511. try:
  512. file_dict = {}
  513. for i, val in enumerate(file_path_list):
  514. file_dict[val] = "{uid}/{channel}/{n_time}_{i}.jpeg".format(uid=uid, channel=channel, # 封面图
  515. n_time=n_time, i=i)
  516. if not reko_result:
  517. logger.info('{}识别结果为空'.format(uid))
  518. return False
  519. if CONFIG_INFO != CONFIG_US: # 目前只上美洲
  520. return False
  521. # 存美洲
  522. session = Session(aws_access_key_id=AWS_ACCESS_KEY_ID[1],
  523. aws_secret_access_key=AWS_SECRET_ACCESS_KEY[1],
  524. region_name="us-west-1")
  525. s3 = session.resource("s3")
  526. bucket = "rekognition-pic-results"
  527. # 上传到S3 rekognition-pic-results
  528. for file_path, upload_path in file_dict.items():
  529. logger.info('{}文件路径{}'.format(uid, file_path))
  530. upload_data = open(file_path, "rb")
  531. s3.Bucket(bucket).put_object(Key=upload_path, Body=upload_data)
  532. # reko结果存储到dynamoDB
  533. event_type = 0
  534. new_bounding_box_dict = ''
  535. if len(labels_data['label_list']) > 0:
  536. event_type = int(labels_data['eventType'])
  537. new_bounding_box_dict = json.dumps(labels_data['new_bounding_box_dict'])
  538. table_name = 'asj_push_message' # 表名称
  539. dynamo = DynamodbObject(AWS_ACCESS_KEY_ID[1], AWS_SECRET_ACCESS_KEY[1], 'us-west-1')
  540. item = {'device_uid': {'S': uid}, # 设备uid
  541. 'event_time': {'N': str(n_time)}, # 设备触发时间戳,也用作S3资源对象名前缀
  542. 'ai_coordinate': {'S': new_bounding_box_dict}, # ai坐标框信息
  543. 'channel': {'N': str(channel)}, # 设备通道号
  544. 'event_type': {'N': str(event_type)}, # 事件类型
  545. 'is_pic': {'N': '3'}, # 1:图片,2:视频,3:多图
  546. 'reko_result': {'S': json.dumps(reko_result)}, # reko识别结果
  547. 'storage_region': {'N': '2'}, # 存储平台1:阿里云,2:AWS
  548. }
  549. result = dynamo.put_item(table_name, item)
  550. logger.info('{}识别后存S3与DynamoDB成功{}'.format(uid, result))
  551. return True
  552. except Exception as e:
  553. logger.info('{}识别后存S3与DynamoDB失败:{}'.format(uid, repr(e)))
  554. return False