Explorar el Código

新增ai推送表,新增ai推送接口

lang hace 3 años
padre
commit
57cf63f765
Se han modificado 2 ficheros con 408 adiciones y 61 borrados
  1. 379 61
      Controller/AiController.py
  2. 29 0
      Model/models.py

+ 379 - 61
Controller/AiController.py

@@ -44,7 +44,7 @@ from Controller.CheckUserData import DataValid
 from Model.models import Device_Info, Order_Model, Store_Meal, VodHlsModel, OssCrdModel, UID_Bucket, StsCrdModel, \
     ExperienceContextModel, Pay_Type, CDKcontextModel, Device_User, SysMassModel, SysMsgModel, UidPushModel, \
     Unused_Uid_Meal, UIDMainUser, UserModel, PromotionRuleModel, VideoPlaybackTimeModel, CloudLogModel, CouponModel, \
-    AiStoreMeal, AiService, UidSetModel
+    AiStoreMeal, AiService, UidSetModel, Ai_Push_Info
 from Object.AWS.S3Email import S3Email
 from Object.AliPayObject import AliPayObject
 from Object.AliSmsObject import AliSmsObject
@@ -60,6 +60,11 @@ from Controller.PaymentCycle import Paypal
 from decimal import Decimal
 from Ansjer.config import SERVER_TYPE
 from Service.ModelService import ModelService
+from Object import MergePic
+import boto3
+import botocore
+from botocore import client
+
 
 
 # AI服务
@@ -79,7 +84,7 @@ class AiView(View):
         if operation is None:
             return response.json(444, 'error path')
         elif operation == 'identification':  # ai识别
-            return self.do_ai_identification(request_dict, response)
+            return self.do_ai_identification(request.POST, response)
         else:
             token = request_dict.get('token', None)
             # 设备主键uid
@@ -95,6 +100,8 @@ class AiView(View):
                 return self.do_change_ai_status(userID, request_dict, response)
             elif operation == 'commoditylist':  # 修改云存状态,传送两个url,即getsignsts接口和storeplaylist接口
                 return self.do_commodity_list(userID, request_dict, response)
+            elif operation == 'identification':  # ai识别
+                return self.do_ai_identification(request_dict, response)
             else:
                 return response.json(414)
 
@@ -234,7 +241,7 @@ class AiView(View):
                 # detectUrl = "{DETECT_PUSH_DOMAIN}AiService/push?etk={etk}&endTime={endTime}". \
                 #     format(etk=etk, DETECT_PUSH_DOMAIN=SERVER_DOMAIN_SSL, endTime=endTime)
                 aiIdentificationUrl = "{DETECT_PUSH_DOMAIN}AiService/identification".format(DETECT_PUSH_DOMAIN=SERVER_DOMAIN_SSL)
-                return response.json(0, {'aiIdentificationUrl':aiIdentificationUrl, 'endTime':endTime, 'etk':etk})
+                return response.json(0, {'aiIdentificationUrl': aiIdentificationUrl, 'endTime': endTime, 'etk': etk})
         else:
             return response.json(14)
 
@@ -328,77 +335,388 @@ class AiView(View):
         return response.json(10, 'generate_order_false')
 
 
-    def do_ai_identification(self, request_dict):
+    def do_ai_identification(self, request_dict,response):
         etk = request_dict.get('etk', None)
+        now_time = int(time.time())
         if etk:
             eto = ETkObject(etk)
             uid = eto.uid
-            file_post_one = request_dict.get('file_one', None)
-            file_post = file_post_one.replace(' ', '+')
-            # file_decode = base64.b64decode(file_post)
-
-            file_post_two = request_dict.get('file_two', None)
+            ##通过uid查出endTime是否过期,并且ai开关是否打开
+            AiServiceQuery = AiService.objects.filter(uid=uid, detect_status=0, use_status=1, endTime__gt=now_time).\
+                values('detect_group')
+            if not AiServiceQuery.exists():
+                return JsonResponse(status=500, data='ai_service_invalid', safe=False)
+            detect_group = AiServiceQuery[0]['detect_group']
+            #{}??
+            #
+            file_post_one = request_dict.get('fileOne', None)
+            file_post_two = request_dict.get('fileTwo', None)
+            file_post_three = request_dict.get('fileThree', None)
+
+            file_post_one = file_post_one.replace(' ', '+')
             file_post_two = file_post_two.replace(' ', '+')
-            # file_decode_two = base64.b64decode(file_post_two)
-
-            now_time = int(time.time())
-            dir_path = os.path.join(BASE_DIR, 'static/ai/')
-            if not os.path.exists(dir_path):
-                os.makedirs(dir_path)
+            file_post_three = file_post_three.replace(' ', '+')
 
-            file_path_one = dir_path + 'one' + str(now_time) + '.jpeg'
-            file_path_two = dir_path + 'two' + str(now_time) + '.jpeg'
+            file_post_one = base64.b64decode(file_post_one)
+            file_post_two = base64.b64decode(file_post_two)
+            file_post_three = base64.b64decode(file_post_three)
 
-            file_list = ['one', 'two']
+            file_list = [file_post_one, file_post_two, file_post_three]
+            del file_post_one, file_post_two, file_post_three
 
+            dir_path = os.path.join(BASE_DIR, 'static/ai/' + uid + '/' + str(now_time))
+            if not os.path.exists(dir_path):
+                os.makedirs(dir_path)
+            file_path_list = []
+            i = 1
             for index in file_list:
-                file_path = dir_path + index + str(now_time) + '.jpeg'
+                file_path = dir_path + '/' + str(i) + '.jpg'
+                file_path_list.append(file_path)
                 with open(file_path, 'wb') as f:
-                    # file_byte = file_post.encode('utf-8')
-                    f.write(file_decode)
-
-            return HttpResponse("seccess")
-            file2 = request.FILES.get('file_one', None)
-            file3 = request.FILES.get('file_two', None)
-            file4 = request.FILES.get('file_three', None)
-
-            print('--------------------------file')
-            print(file)
-
-            print('===========================post_file')
-            print(file_post)
-
-            post_file_list = [file, file2, file3, file4]
-            file_list = []
-            for index in range(len(post_file_list)):
-                if post_file_list[index]:
-                    file_list.append(post_file_list[index])
-
-            del post_file_list
-            if len(file_list) > 1:
-                merge = []
-                now_time = int(time.time())
-                dir_path = os.path.join(BASE_DIR, 'static/', str(now_time))
-                if not os.path.exists(dir_path):
-                    os.makedirs(dir_path)
-                for item in file_list:
-                    if hasattr(item, 'name'):
-                        file_path = os.path.join(dir_path, item.name)
-                        with open(file_path, 'wb') as f:
-                            for c in item.chunks():
-                                f.write(c)
-                                merge.append(file_path)
-
-                image_size = 500  # 每张小图片的大小
-                image_colnum = 2  # 合并成一张图后,一行有几个小图
-                MergePic.merge_images(dir_path, image_size, image_colnum)
-                # return HttpResponse(dir_path + '.jpg')
-                photo = open(dir_path + '.jpg', 'rb')
-            else:
-                photo = file_list[0]
+                    f.write(index)
+                    f.close()
+                i += 1
+
+            image_size = 500  # 每张小图片的大小
+            image_colnum = 1  # 合并成一张图后,一行有几个小图
+            MergePic.merge_images(dir_path, image_size, image_colnum)
+            photo = open(dir_path + '.jpg', 'rb')  #打开合成图
+
+            cover = dir_path + '/' + str(i-1) + '.jpg'
+            desc = dir_path + '.jpg'
+            # photo = open(r'E:\test---------------\test\snipaste20220121_215952.jpg', 'rb')
+            #识别合成图片
+            maxLabels = 50
+            minConfidence = 96
+            try:
+                client = boto3.client(
+                    'rekognition',
+                    aws_access_key_id='AKIA2E67UIMD6JD6TN3J',
+                    aws_secret_access_key='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',
+                    region_name='us-east-1')
+                # doc:
+                rekognition_res = client.detect_labels(
+                    Image={
+                        'Bytes': photo.read()},
+                    MaxLabels=maxLabels,
+                    MinConfidence=minConfidence)
+                if rekognition_res['ResponseMetadata']['HTTPStatusCode'] != 200:
+                    return response.json(173)
+                labels =rekognition_res['Labels']
+                label_name = []
+                for label in labels:
+                    label_name.append(label['Name'])
+                    for Parents in label['Parents']:
+                        label_name.append(Parents['Name'])
+                labels = self.checkLabels(detect_group, label_name)    #检查标签是否符合用户选择的识别类型
+                if len(labels['label_list']) == 0:
+                    return JsonResponse(status=500, data='label_list_none')
+                event_type = ','.join(labels['label_type'])
+
+                #存储消息以及推送
+                channel = request_dict.get('channel', '1')
+                n_time = now_time
+                # event_type = request_dict.get('event_type', None)
+
+                is_st = 1  #单图
+                region = 1
+                # uid = request_dict.get('uid', None)     # 调试
+                # 判断uid长度
+                if len(uid) != 20 and len(uid) != 14:
+                    return JsonResponse(status=200, data={'code': 404, 'msg': 'wrong uid'})
+
+                # pkey = '{uid}_{channel}_{event_type}_ptl'.format(uid=uid, channel=channel, event_type=event_type)
+                # redisObj = RedisObject(db=6)
+                # have_pkey = redisObj.get_data(key=pkey)  # 一分钟限制key
+                #
+                # # 一分钟内不推送
+                # if have_pkey:
+                #     return JsonResponse(status=200, data={'code': 0, 'msg': 'Push again in one minute'})
+                # redisObj.set_data(key=pkey, val=1, expire=60)
+
+                # 查询推送数据
+                uid_push_qs = UidPushModel.objects.filter(uid_set__uid=uid). \
+                    values('token_val', 'app_type', 'appBundleId', 'm_code', 'push_type', 'userID_id',
+                           'userID__NickName',
+                           'lang', 'm_code', 'tz', 'uid_set__nickname', 'uid_set__detect_interval',
+                           'uid_set__detect_group',
+                           'uid_set__channel')
+                if not uid_push_qs.exists():
+                    return JsonResponse(status=200, data={'code': 176, 'msg': 'no uid_push data'})
+                redis_list = []
+                for qs in uid_push_qs:
+                    redis_list.append(qs)
+
+                nickname = redis_list[0]['uid_set__nickname']
+
+                if not nickname:
+                    nickname = uid
+
+                kwag_args = {
+                    'uid': uid,
+                    'channel': channel,
+                    'event_type': event_type,
+                    'n_time': n_time,
+                }
+                eq_list = []
+                userID_ids = []
+                do_apns_code = ''
+                do_fcm_code = ''
+                do_jpush_code = ''
+                for up in redis_list:
+                    # push_type = up['push_type']
+                    # appBundleId = up['appBundleId']
+                    # token_val = up['token_val']
+                    # lang = up['lang']
+                    # tz = up['tz']
+                    # if tz is None or tz == '':
+                    #     tz = 0
+
+                    # 发送标题
+                    # msg_title = self.get_msg_title(appBundleId=appBundleId, nickname=nickname)
+                    # # 发送内容
+                    # msg_text = self.get_msg_text(channel=channel, n_time=n_time, lang=lang, tz=tz,
+                    #                              event_type=event_type)
+                    # kwag_args['appBundleId'] = appBundleId
+                    # kwag_args['token_val'] = token_val
+                    # kwag_args['msg_title'] = msg_title
+                    # kwag_args['msg_text'] = msg_text
+                    # 推送消息
+                    # if push_type == 0:  # ios apns
+                    #     do_apns_code = self.do_apns(**kwag_args)
+                    # elif push_type == 1:  # android gcm
+                    #     do_fcm_code = self.do_fcm(**kwag_args)
+                    # elif push_type == 2:  # android jpush
+                    #     do_jpush_code = self.do_jpush(**kwag_args)
+                    # 以下是存库
+                    userID_id = up["userID_id"]
+                    if userID_id not in userID_ids:
+                        now_time = int(time.time())
+                        eq_list.append(Ai_Push_Info(
+                            userID_id=userID_id,
+                            eventTime=n_time,
+                            eventType=event_type,
+                            devUid=uid,
+                            devNickName=nickname,
+                            Channel=channel,
+                            alarm='检查到{labels} \tChannel:{channel}'.format(labels=','.join(labels['label_list']), channel=channel),
+                            is_st=is_st,
+                            receiveTime=n_time,
+                            addTime=now_time,
+                            storage_location=2
+                        ))
+                        userID_ids.append(userID_id)
+                Ai_Push_Info.objects.bulk_create(eq_list)
+
+                #上传缩略图到s3
+                upload_cover_path = "{uid}/{channel}/cover{n_time}.jpg".format(uid=uid, channel=channel, n_time=n_time)  #封面图
+                upload_desc_path = "{uid}/{channel}/desc{n_time}.jpg".format(uid=uid, channel=channel, n_time=n_time)   #详情内容图
+                c_res = self.upload_s3(cover, upload_cover_path)
+                d_res = self.upload_s3(desc, upload_desc_path)
+                if c_res and d_res:
+                    return JsonResponse(status=200, data='success', safe=False)
+                return JsonResponse(status=500, data='fail', safe=False)
+
+            except Exception as e:
+                print(e)
+                return response.json(500, repr(e))
+
+
 
 
         else:
             return HttpResponse("fail")
 
 
+    ## 检查是否有符合条件的标签
+    def checkLabels(self, user_detect_group, labels):
+        labels_type = {
+            '1': ['Person', 'Human'],    #人
+            '2': ['Dog', 'Pet', 'Canine', 'Animal'],   #动物
+            '3': ['Car', '', 'Vehicle', 'Transportation', 'Automobile']   #车
+        }
+        user_detect_list = user_detect_group.split(',')
+        user_labels_type = {}
+        for user_detect in user_detect_list:
+            if user_detect in labels_type.keys():
+                user_labels_type[user_detect] = labels_type[user_detect]
+        label_list = []
+        for k, labels_type in user_labels_type.items():
+            for label in labels_type:
+                if label in labels:
+                    label_list.append(label)
+        return {'label_type': user_labels_type.keys(), 'label_list': label_list}
+
+
+    def upload_s3(self, file_path, upload_path):
+        try:
+            aws_key = "AKIA2MMWBR4DSFG67DTG" #【你的 aws_access_key】
+            aws_secret = "aI9gxcAKPmiGgPy9axrtFKzjYGbvpuytEX4xWweL" # 【你的 aws_secret_key】
+            session = Session(aws_access_key_id=aws_key,
+                              aws_secret_access_key=aws_secret,
+                              region_name="cn-northwest-1")
+            s3 = session.resource("s3")
+            # client = session.client("s3")
+            bucket = "aipush" # 【你 bucket 的名字】 # 首先需要保.证 s3 上已经存在该存储桶,否则报错
+            upload_data = open(file_path, "rb")
+            # upload_key = "test"
+            s3.Bucket(bucket).put_object(Key=upload_path, Body=upload_data)
+            return True
+        except Exception as e:
+            print(repr(e))
+            return False
+
+    def get_msg_title(self, appBundleId, nickname):
+        package_title_config = {
+            'com.ansjer.customizedd_a': 'DVS',
+            'com.ansjer.zccloud_a': 'ZosiSmart',
+            'com.ansjer.zccloud_ab': '周视',
+            'com.ansjer.adcloud_a': 'ADCloud',
+            'com.ansjer.adcloud_ab': 'ADCloud',
+            'com.ansjer.accloud_a': 'ACCloud',
+            'com.ansjer.loocamccloud_a': 'Loocam',
+            'com.ansjer.loocamdcloud_a': 'Anlapus',
+            'com.ansjer.customizedb_a': 'COCOONHD',
+            'com.ansjer.customizeda_a': 'Guardian365',
+            'com.ansjer.customizedc_a': 'PatrolSecure',
+        }
+        if appBundleId in package_title_config.keys():
+            return package_title_config[appBundleId] + '(' + nickname + ')'
+        else:
+            return nickname
+
+    def is_sys_msg(self, event_type):
+        event_type_list = [702, 703, 704]
+        if event_type in event_type_list:
+            return True
+        return False
+
+    def get_msg_text(self, channel, n_time, lang, tz, event_type, is_sys=0):
+        n_date = CommonService.get_now_time_str(n_time=n_time, tz=tz,lang=lang)
+        etype = int(event_type)
+        if lang == 'cn':
+            if etype == 704:
+                msg_type = '电量过低'
+            elif etype == 702:
+                msg_type = '摄像头休眠'
+            elif etype == 703:
+                msg_type = '摄像头唤醒'
+            else:
+                msg_type = ''
+            if is_sys:
+                send_text = '{msg_type} 通道:{channel}'.format(msg_type=msg_type, channel=channel)
+            else:
+                send_text = '{msg_type} 通道:{channel} 日期:{date}'.format(msg_type=msg_type, channel=channel, date=n_date)
+                # send_text = '{msg_type} 通道:{channel} 日期:{date}'.format(msg_type=msg_type, channel=channel, date=n_date)
+        else:
+            if etype == 704:
+                msg_type = 'Low battery'
+            elif etype == 702:
+                msg_type = 'Camera sleep'
+            elif etype == 703:
+                msg_type = 'Camera wake'
+            else:
+                msg_type = ''
+            if is_sys:
+                send_text = '{msg_type} channel:{channel}'. \
+                    format(msg_type=msg_type, channel=channel)
+            else:
+                send_text = '{msg_type} channel:{channel} date:{date}'. \
+                    format(msg_type=msg_type, channel=channel, date=n_date)
+        return send_text
+
+    def do_jpush(self, uid, channel, appBundleId, token_val, event_type, n_time,
+                 msg_title, msg_text):
+        app_key = JPUSH_CONFIG[appBundleId]['Key']
+        master_secret = JPUSH_CONFIG[appBundleId]['Secret']
+        # 此处换成各自的app_key和master_secre
+        _jpush = jpush.JPush(app_key, master_secret)
+        push = _jpush.create_push()
+        # if you set the logging level to "DEBUG",it will show the debug logging.
+        # _jpush.set_logging("DEBUG")
+        # push.audience = jpush.all_
+        push.audience = jpush.registration_id(token_val)
+        push_data = {"alert": "Motion ", "event_time": n_time, "event_type": event_type, "msg": "",
+                     "received_at": n_time, "sound": "sound.aif", "uid": uid, "zpush": "1", "channel": channel}
+        android = jpush.android(alert=msg_text, priority=1, style=1, alert_type=7,
+                                big_text=msg_text, title=msg_title,
+                                extras=push_data)
+        push.notification = jpush.notification(android=android)
+        push.platform = jpush.all_
+        res = push.send()
+        print(res)
+        return res.status_code
+        # try:
+        #     res = push.send()
+        #     print(res)
+        # except Exception as e:
+        #     print("jpush fail")
+        #     print("Exception")
+        #     print(repr(e))
+        #     return
+        # else:
+        #     print("jpush success")
+        #     return
+
+    def do_fcm(self, uid, channel, appBundleId, token_val, event_type, n_time, msg_title, msg_text):
+        try:
+            serverKey = FCM_CONFIG[appBundleId]
+        except Exception as e:
+            return 'serverKey abnormal'
+        push_service = FCMNotification(api_key=serverKey)
+        data = {"alert": "Motion ", "event_time": n_time, "event_type": event_type, "msg": "",
+                "received_at": n_time, "sound": "sound.aif", "uid": uid, "zpush": "1", "channel": channel}
+        result = push_service.notify_single_device(registration_id=token_val, message_title=msg_title,
+                                                   message_body=msg_text, data_message=data,
+                                                   extra_kwargs={
+                                                       'default_vibrate_timings': True,
+                                                       'default_sound': True,
+                                                       'default_light_settings': True
+                                                   })
+        print('fcm push ing')
+        print(result)
+        return result
+
+    def do_apns(self, uid, channel, appBundleId, token_val, event_type, n_time, msg_title,
+                msg_text):
+        logger = logging.getLogger('info')
+        logger.info("进来do_apns函数了")
+        logger.info(token_val)
+        logger.info(APNS_MODE)
+        logger.info(os.path.join(BASE_DIR, APNS_CONFIG[appBundleId]['pem_path']))
+        try:
+            cli = apns2.APNSClient(mode=APNS_MODE,
+                                   client_cert=os.path.join(BASE_DIR, APNS_CONFIG[appBundleId]['pem_path']))
+
+            push_data = {"alert": "Motion ", "event_time": n_time, "event_type": event_type, "msg": "",
+                         "received_at": n_time, "sound": "", "uid": uid, "zpush": "1", "channel": channel}
+            alert = apns2.PayloadAlert(body=msg_text, title=msg_title)
+            payload = apns2.Payload(alert=alert, custom=push_data, sound="default")
+
+            # return uid, channel, appBundleId, str(token_val), event_type, n_time, msg_title,msg_text
+            n = apns2.Notification(payload=payload, priority=apns2.PRIORITY_LOW)
+            res = cli.push(n=n, device_token=token_val, topic=appBundleId)
+            print(res.status_code)
+            logger.info("推送状态:")
+            logger.info(res.status_code)
+
+            #     200, 推送成功。
+            #   400, 请求有问题。
+            #   403, 证书或Token有问题。
+            #   405, 请求方式不正确, 只支持POST请求
+            #   410, 设备的Token与证书不一致
+            if res.status_code == 200:
+                return res.status_code
+            else:
+                print('apns push fail')
+                print(res.reason)
+                logger.info('apns push fail')
+                logger.info(res.reason)
+                return res.status_code
+        except (ValueError, ArithmeticError):
+            return 'The program has a numeric format exception, one of the arithmetic exceptions'
+        except Exception as e:
+            print(repr(e))
+            logger.info(repr(e))
+            return repr(e)
+

+ 29 - 0
Model/models.py

@@ -343,6 +343,35 @@ class Equipment_Info(models.Model):
         ordering = ('-id',)
         app_label = "db2"
 
+class Ai_Push_Info(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    devUid = models.CharField(default='', db_index=True, blank=True, max_length=32, verbose_name=u'设备ID')
+    devNickName = models.CharField(blank=True, max_length=32, default='', verbose_name=u'设备昵称')
+    Channel = models.IntegerField(default=1, blank=True, verbose_name=u'设备通道')
+    eventType = models.CharField(blank=True, max_length=100, default='', verbose_name=u'事件类型')
+    status = models.BooleanField(blank=True, default=False, verbose_name=u'事件状态')
+    alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
+    eventTime = models.CharField(blank=True, default='', max_length=16, verbose_name=u'设备报警时间')
+    receiveTime = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
+    userID_id = models.CharField(default='',  db_index=True, blank=True, max_length=32, verbose_name=u'用户ID')
+    is_st = models.SmallIntegerField(default=0, verbose_name='是否截图')  # 0 否,1 是图,2,视频
+    storage_location = models.SmallIntegerField(default=1, db_index=True, verbose_name='数据信息存储位置。1:阿里云oss,2:aws')
+    # message_id = models.CharField(blank=True, max_length=32, default='', verbose_name='第三方推送服务器返回的id')
+    # push_type = models.SmallIntegerField(blank=True, default=0, verbose_name='第三方推送服务器标志。0:APNS推送,1:谷歌推送,2:极光推送')
+    # push_server_status = models.IntegerField(blank=True, default=200, verbose_name='是否成功推送到第三方服务器。200:成功,other:失败')
+    # push_device_status = models.SmallIntegerField(blank=True, default=-1, verbose_name='是否成功推送到目标设备。0:失败,1:成功')
+    addTime = models.IntegerField(verbose_name='添加时间', default=0)
+
+    def __str__(self):
+        return self.id
+
+    class Meta:
+        db_table = 'ai_push_info'
+        verbose_name = u'ai信息推送表'
+        verbose_name_plural = verbose_name
+        ordering = ('-id',)
+
+
 class StatResModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name='自动ID')
     name = models.CharField(default='', max_length=120, verbose_name='图片名称', unique=True)