Pārlūkot izejas kodu

AI消息推送整合OCI对象存储

zhangdongming 1 gadu atpakaļ
vecāks
revīzija
39933542db

+ 19 - 0
AnsjerPush/config.py

@@ -213,3 +213,22 @@ XM_PUSH_CHANNEL_ID = {
 
 firebase_admin.initialize_app(credentials.Certificate(
     BASE_DIR + '/static/fcm/adcloud-fdf9b-firebase-adminsdk-dcvn1-d53e047cc8.json'))
+
+
+OCI_CONFIG = {
+    'us': {
+        'user': 'ocid1.user.oc1..aaaaaaaa63vtn64izdujrghlfby6xrlrrdce4yldtnjm7tmqzoc5i2b36s5q',
+        'fingerprint': '09:ff:f4:fa:64:bd:7b:72:64:67:5e:9a:ba:01:68:7b',
+        'tenancy': 'ocid1.tenancy.oc1..aaaaaaaaemreyqoegf4wbegfzetg63bwvzxa7ahfptbziexslzfmc7gnuwmq',
+        'region': 'us-phoenix-1',
+        'key_file': 'AnsjerPush/servers@ansjer.com_2023-12-20T07_21_33.069Z.pem'
+    },
+    'eur': {
+        'user': 'ocid1.user.oc1..aaaaaaaa63vtn64izdujrghlfby6xrlrrdce4yldtnjm7tmqzoc5i2b36s5q',
+        'fingerprint': '09:ff:f4:fa:64:bd:7b:72:64:67:5e:9a:ba:01:68:7b',
+        'tenancy': 'ocid1.tenancy.oc1..aaaaaaaaemreyqoegf4wbegfzetg63bwvzxa7ahfptbziexslzfmc7gnuwmq',
+        'region': 'uk-london-1',
+        'key_file': 'AnsjerPush/servers@ansjer.com_2023-12-20T07_21_33.069Z.pem'
+    }
+}
+OCI_NAMESPACE_NAME = 'cnmlmfa4fooi'

+ 28 - 0
AnsjerPush/servers@ansjer.com_2023-12-20T07_21_33.069Z.pem

@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCRP0y7XdQ04WV7
+pMGtdCMx5Kdq+NIBzCNSbn4sEzjsAGnmqNuJYLYDtKZaWZp2xwq3+0EoRiHkN+P9
+Jrzb5MplbAzGEDWMevdYdqCxPL0H+KIEd2Zy7e3npYUipQ56astPq/9HytwvfbsL
+5ED8/csRqyPy8/JfuRlQ/i7XhhAG7HNx+hEVaiJLhfi0Y7IYX5+Zx4040fmDybfE
+J+IGB0qYNm/OfPIK8x8lr3RcOla86nFPrkgbxQOW1c0hbZ5NYILBJuzhCDsiU62A
+3o557ur8Tr2xAeS3ZVtW1yzbqwZwMyRtN0Anl3inVrSyDgXcEjWlckCi24OVnu2F
+QAd1d4ujAgMBAAECggEAClQyjDZ5c0M+GMNYJJIYOKGWiERmhssyDdger9q0FxBW
+d5k1d3kBqJTNqaoqklzINdovwYHvQg/5bhS1pHuKKxk6dVFMxY8vDMLu3XvAw5La
+TrABAJZL70e1hoevVmRGzgUgs8XIz7XEue1C89rGeJyvg0T2zPjYRIq24Qu/Ewbd
+JvVmjz4nAe28VjgEwzOnrPFkykT9YojUF1Bl26dJBj+oVk+O6Jf74TMhoT9O/B35
+VGDypqm2qyQQ9ra8myNKmTOCpi1RiK433k6RRCywyf6o+Lehot31eFFO6caIayVG
+j2aWe5N2gaWBPGeioFInKXqkw4tjLafWb3oEDJpAdQKBgQDD9CY8M9K3GQekE0Fb
+dh6a6Aza47WXdoOP/wnO+w3DsaqL42ZCp5/L3D3LtNBJiHXQZhXTuciV5qEtjszt
+XquXYJqyz29A7SNLOXLilvjPq71qWzJF6ViWcHBjX1R/7XqJkK0FuaJWaQFJ5uvS
+kEw55IrKnJ8DQ4m1ZJECn4nWLwKBgQC9wWpkmNNOTLyNJ5Ukf5IE2onL3aaa7iUG
+nLCXCUOXBUUGt9FE9As0PdNjXeTqqH80mWIEgyTBkvFNG5yGwNiVVIMd4Sa9Sm7W
+GND1NFeU3TDJ00rV9FSnVSbrJywi8NEst7qZqy4CS7xjr1+qP6xqIKhHS9n4+K8S
+idlsWB94zQKBgFUv7+teMC3vULYQtOoZGMcJOIV0Vv6IxDs2icIUvHAl7dmwu0Ug
+8ERE9Ax6B87f5y/5IWYRL1WTlOBkY0ySSpCdq8MukNQuA5jxWbOOJI7Lv6XcDaf9
+AMkuCn349JhE2m+xmLaTdDKSpb/GByFcH/dPFtNscWiO1PApzyzPxLF7AoGAMZ8M
+pXXZfBZREFCTjdHWa3KCqk8yLD2ubQY4n6aKiEmWfWVAUlnHPEgWqVt6a2rYqPab
+TTbGO+CjPVjFG+/+Mz7AcuXX7ZQzW8Vtj1G6vXECOyUH4t9b6842uTOrNQ/og1sg
+buL2yx7nCuJnj+vKuI4Fs29Adv0BO0XVF6ILyNkCgYAvP+bOLbPCS3u9Sw23e63t
+9EqeyNfR88KmQzVQGcP5yL3yUytQp5RrDqDdndP3uQa1TY6WQLKPqMh7sMWH9yWB
+6B/CudtduRWbWxLjXVN8Lhb9w7ORLRcY23xDQwdueOER3PHnp3UwaebHJ4+JXcdA
+KtygcG+9e3hWuUzyV/QdLQ==
+-----END PRIVATE KEY-----

+ 38 - 29
Controller/AiController.py

@@ -10,12 +10,12 @@ import base64
 import json
 import logging
 import os
+import threading
 import time
 
 import apns2
 import boto3
 import jpush
-from PIL import UnidentifiedImageError
 from boto3.session import Session
 from django.views.generic.base import View
 from pyfcm import FCMNotification
@@ -24,10 +24,13 @@ from AnsjerPush.config import AI_IDENTIFICATION_TAGS_DICT, CONFIG_US, CONFIG_EUR
 from AnsjerPush.config import AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, APNS_MODE, APNS_CONFIG, BASE_DIR, \
     JPUSH_CONFIG, FCM_CONFIG
 from AnsjerPush.config import CONFIG_INFO
+from AnsjerPush.config import PUSH_BUCKET
 from Model.models import UidPushModel, AiService, VodHlsTag, VodHlsTagType
 from Object import MergePic
 from Object.DynamodbObject import DynamodbObject
 from Object.ETkObject import ETkObject
+from Object.OCIObjectStorage import OCIObjectStorage
+from Object.RedisObject import RedisObject
 from Object.ResponseObject import ResponseObject
 from Object.SageMakerAiObject import SageMakerAiObject
 from Object.TokenObject import TokenObject
@@ -35,8 +38,6 @@ from Object.enums.MessageTypeEnum import MessageTypeEnum
 from Service.CommonService import CommonService
 from Service.DevicePushService import DevicePushService
 from Service.EquipmentInfoService import EquipmentInfoService
-from Object.RedisObject import RedisObject
-import threading
 
 TIME_LOGGER = logging.getLogger('time')
 
@@ -299,6 +300,7 @@ class AiView(View):
             nickname = uid
 
         userID_ids = []
+        region = 4 if CONFIG_INFO == CONFIG_EUR else 3
         for up in uid_push_list:
             push_type = up['push_type']
             appBundleId = up['appBundleId']
@@ -323,7 +325,7 @@ class AiView(View):
                     alarm=label_str,
                     is_st=3,
                     add_time=now_time,
-                    storage_location=2,
+                    storage_location=region,
                     border_coords=json.dumps(new_bounding_box_dict)
                 )
                 userID_ids.append(userID_id)
@@ -485,35 +487,42 @@ class AiView(View):
 
     def upload_s3(self, file_dict, dir_path):
         try:
-            if CONFIG_INFO == CONFIG_US or CONFIG_INFO == CONFIG_EUR:
-                # 存国外
-                aws_key = AWS_ACCESS_KEY_ID[1]
-                aws_secret = AWS_SECRET_ACCESS_KEY[1]
-                session = Session(aws_access_key_id=aws_key,
-                                  aws_secret_access_key=aws_secret,
-                                  region_name="us-east-1")
-                s3 = session.resource("s3")
-                bucket = "foreignpush"
-            else:
-                # 存国内
-                aws_key = AWS_ACCESS_KEY_ID[0]
-                aws_secret = AWS_SECRET_ACCESS_KEY[0]
-                session = Session(aws_access_key_id=aws_key,
-                                  aws_secret_access_key=aws_secret,
-                                  region_name="cn-northwest-1")
-                s3 = session.resource("s3")
-                bucket = "push"
-
+            # if CONFIG_INFO == CONFIG_US or CONFIG_INFO == CONFIG_EUR:
+            #     # 存国外
+            #     aws_key = AWS_ACCESS_KEY_ID[1]
+            #     aws_secret = AWS_SECRET_ACCESS_KEY[1]
+            #     session = Session(aws_access_key_id=aws_key,
+            #                       aws_secret_access_key=aws_secret,
+            #                       region_name="us-east-1")
+            #     s3 = session.resource("s3")
+            #     bucket = "foreignpush"
+            # else:
+            #     # 存国内
+            #     aws_key = AWS_ACCESS_KEY_ID[0]
+            #     aws_secret = AWS_SECRET_ACCESS_KEY[0]
+            #     session = Session(aws_access_key_id=aws_key,
+            #                       aws_secret_access_key=aws_secret,
+            #                       region_name="cn-northwest-1")
+            #     s3 = session.resource("s3")
+            #     bucket = "push"
+            #
+            # for file_path, upload_path in file_dict.items():
+            #     print('-------')
+            #     print(file_path)
+            #     print('-------')
+            #     upload_data = open(file_path, "rb")
+            #     # upload_key = "test"
+            #     s3.Bucket(bucket).put_object(Key=upload_path, Body=upload_data)
+            region = 'eur' if CONFIG_INFO == CONFIG_EUR else 'us'
+            oci = OCIObjectStorage(region)
             for file_path, upload_path in file_dict.items():
-                print('-------')
-                print(file_path)
-                print('-------')
                 upload_data = open(file_path, "rb")
-                # upload_key = "test"
-                s3.Bucket(bucket).put_object(Key=upload_path, Body=upload_data)
+                # OCI上传对象
+                oci.put_object(PUSH_BUCKET, upload_path, upload_data, 'image/jpeg')
             return True
         except Exception as e:
-            print(repr(e))
+            TIME_LOGGER.error('rekoAI上传对象异常errLine={errLine}, errMsg={errMsg}'
+                              .format(errLine=e.__traceback__.tb_lineno, errMsg=repr(e)))
             return False
 
     def get_msg_title(self, appBundleId, nickname):

+ 139 - 0
Object/OCIObjectStorage.py

@@ -0,0 +1,139 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : OCIObjectStorage.py
+@Time    : 2024/4/10 15:06
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import logging
+
+import oci
+
+from AnsjerPush.config import OCI_CONFIG, OCI_NAMESPACE_NAME
+
+LOGGER = logging.getLogger('time')
+
+
+class OCIObjectStorage:
+
+    # Create a default oci_config using DEFAULT profile in default location
+    # Refer to
+    # https://docs.cloud.oracle.com/en-us/iaas/Content/API/Concepts/sdkconfig.htm#SDK_and_CLI_Configuration_File
+    # for more info
+
+    def __init__(self, region):
+        # Initialize service client with default oci_config file
+        self.object_storage_client = oci.object_storage.ObjectStorageClient(OCI_CONFIG[region])
+
+    def create_ereauthenticated_request(self, bucket_name, name, object_name, time_expires):
+        """
+        创建特定于桶的预认证请求。
+        api:https://docs.oracle.com/en-us/iaas/api/#/en/objectstorage/20160918/PreauthenticatedRequest/CreatePreauthenticatedRequest
+        @param bucket_name: 存储桶名称
+        @param name: 请求名称 是创建的预授权链接的名称,是方便管理用的,不会影响功能。比如对每个桶分别创建链接,如果要删除或者查看,可以根据name看出来是对哪个桶的链接。
+        @param object_name: 对象名
+        @param time_expires: 失效时间 需要datetime类型格式 例如:datetime.utcnow() + timedelta(minutes=30)
+        @return: 预认证请求URL
+        """
+        try:
+            object_storage_client = self.object_storage_client
+
+            # Send the request to service, some parameters are not required, see API
+            # doc for more info
+            response = object_storage_client.create_preauthenticated_request(
+                namespace_name=OCI_NAMESPACE_NAME,
+                bucket_name=bucket_name,
+                create_preauthenticated_request_details=oci.object_storage.models.CreatePreauthenticatedRequestDetails(
+                    name=name,
+                    access_type="AnyObjectWrite",
+                    time_expires=time_expires,
+                    bucket_listing_action="Deny",
+                    object_name=object_name))
+
+            assert response.status == 200
+            return response.data
+
+        except Exception as e:
+            LOGGER.error('OCI创建预认证URL异常errLine={errLine}, errMsg={errMsg}'
+                         .format(errLine=e.__traceback__.tb_lineno, errMsg=repr(e)))
+            return None
+
+    def get_preauthenticated_request_url(self, bucket_name, name, object_name, time_expires):
+        """
+        获取指定对象预认证请求URL。
+        @param bucket_name: 存储桶名称
+        @param name: 请求名称 是创建的预授权链接的名称,是方便管理用的,不会影响功能。比如对每个桶分别创建链接,如果要删除或者查看,可以根据name看出来是对哪个桶的链接。
+        @param object_name: 对象名
+        @param time_expires: 失效时间 需要datetime类型格式 例如:datetime.utcnow() + timedelta(minutes=30)
+        @return: 预认证请求URL
+        """
+        try:
+            object_storage_client = self.object_storage_client
+            # 创建预认证请求
+            response = object_storage_client.create_preauthenticated_request(
+                namespace_name=OCI_NAMESPACE_NAME,
+                bucket_name=bucket_name,
+                create_preauthenticated_request_details=oci.object_storage.models.CreatePreauthenticatedRequestDetails(
+                    name=name,
+                    object_name=object_name,
+                    access_type="ObjectRead",
+                    time_expires=time_expires
+                )
+            )
+
+            assert response.status == 200
+            return response.data
+
+        except Exception as e:
+            LOGGER.error('OCI获取预认证URL异常errLine={errLine}, errMsg={errMsg}'
+                         .format(errLine=e.__traceback__.tb_lineno, errMsg=repr(e)))
+            return None
+
+    def put_object(self, bucket_name, object_name, obj, content_type=None):
+        """
+        上传对象
+        @param bucket_name: 存储桶名称
+        @param object_name: 对象名
+        @param obj: 数据内容
+        @param content_type: 文件类型
+        @return: 可访问对象URL
+        """
+        try:
+            object_storage_client = self.object_storage_client
+
+            # 发送上传请求
+            put_object_response = object_storage_client.put_object(
+                namespace_name=OCI_NAMESPACE_NAME,
+                bucket_name=bucket_name,
+                object_name=object_name,
+                put_object_body=obj,
+                content_type=content_type
+            )
+
+            # 打印响应头信息
+            assert put_object_response.status == 200
+        except Exception as e:
+            LOGGER.error('OCI上传对象异常errLine={errLine}, errMsg={errMsg}'
+                         .format(errLine=e.__traceback__.tb_lineno, errMsg=repr(e)))
+            return None
+
+    def delete_object(self, bucket_name, object_name, content_type=None):
+        """
+        删除对象
+        @param bucket_name: 存储桶名称
+        @param object_name: 对象名
+        @param content_type: 文件类型
+        @return: 可访问对象URL
+        """
+        try:
+            object_storage_client = self.object_storage_client
+            # 发送删除请求
+            object_storage_client.delete_object(
+                namespace_name=OCI_NAMESPACE_NAME,
+                bucket_name=bucket_name,
+                object_name=object_name)
+        except Exception as e:
+            LOGGER.error('OCI删除对象异常errLine={errLine}, errMsg={errMsg}'
+                         .format(errLine=e.__traceback__.tb_lineno, errMsg=repr(e)))
+            return None

+ 37 - 31
Object/SageMakerAiObject.py

@@ -13,16 +13,17 @@ import threading
 import time
 from io import BytesIO
 
-import boto3
 import cv2
 import numpy as np
 from PIL import Image, UnidentifiedImageError
 
 from AnsjerPush.Config.aiConfig import AI_IDENTIFICATION_TAGS_DICT
-from AnsjerPush.config import AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, CONFIG_US, CONFIG_EUR
+from AnsjerPush.config import CONFIG_EUR
 from AnsjerPush.config import CONFIG_INFO
+from AnsjerPush.config import PUSH_BUCKET
 from Controller import AiController
 from Object.AiEngineObject import AiEngine
+from Object.OCIObjectStorage import OCIObjectStorage
 from Object.enums.MessageTypeEnum import MessageTypeEnum
 from Service.EquipmentInfoService import EquipmentInfoService
 from Service.HuaweiPushService.HuaweiPushService import HuaweiPushObject
@@ -163,13 +164,14 @@ class SageMakerAiObject:
             event_type = res['event_type']
             coords = json.dumps(res['coords']) if res['coords'] else ''  # 坐标框字典转json字符串
             now_time = int(time.time())
+            region = 4 if CONFIG_INFO == CONFIG_EUR else 3
             # 推送表存储数据
             equipment_info_kwargs = {
                 'device_uid': uid,
                 'device_nick_name': nickname,
                 'channel': channel,
                 'is_st': 3,
-                'storage_location': 2,
+                'storage_location': region,
                 'event_type': event_type,
                 'event_time': d_push_time,
                 'add_time': now_time,
@@ -306,45 +308,49 @@ class SageMakerAiObject:
         """
         上传图片到S3
         """
-        if CONFIG_INFO == CONFIG_US or CONFIG_INFO == CONFIG_EUR:
-            # 创建 AWS 访问密钥
-            aws_key = AWS_ACCESS_KEY_ID[1]
-            aws_secret = AWS_SECRET_ACCESS_KEY[1]
-            # 创建会话对象
-            session = boto3.Session(
-                aws_access_key_id=aws_key,
-                aws_secret_access_key=aws_secret,
-                region_name="us-east-1"
-            )
-            s3_resource = session.resource("s3")
-            bucket_name = "foreignpush"
-        else:
-            # 存国内
-            aws_key = AWS_ACCESS_KEY_ID[0]
-            aws_secret = AWS_SECRET_ACCESS_KEY[0]
-            session = boto3.Session(
-                aws_access_key_id=aws_key,
-                aws_secret_access_key=aws_secret,
-                region_name="cn-northwest-1")
-            s3_resource = session.resource("s3")
-            bucket_name = "push"
+        # if CONFIG_INFO == CONFIG_US or CONFIG_INFO == CONFIG_EUR:
+        #     # 创建 AWS 访问密钥
+        #     aws_key = AWS_ACCESS_KEY_ID[1]
+        #     aws_secret = AWS_SECRET_ACCESS_KEY[1]
+        #     # 创建会话对象
+        #     session = boto3.Session(
+        #         aws_access_key_id=aws_key,
+        #         aws_secret_access_key=aws_secret,
+        #         region_name="us-east-1"
+        #     )
+        #     s3_resource = session.resource("s3")
+        #     bucket_name = "foreignpush"
+        # else:
+        #     # 存国内
+        #     aws_key = AWS_ACCESS_KEY_ID[0]
+        #     aws_secret = AWS_SECRET_ACCESS_KEY[0]
+        #     session = boto3.Session(
+        #         aws_access_key_id=aws_key,
+        #         aws_secret_access_key=aws_secret,
+        #         region_name="cn-northwest-1")
+        #     s3_resource = session.resource("s3")
+        #     bucket_name = "push"
 
         try:
+            region = 'eur' if CONFIG_INFO == CONFIG_EUR else 'us'
+            oci = OCIObjectStorage(region)
             # 解码base64字符串为图像数据
             for index, pic in enumerate(file_list):
                 image_data = base64.b64decode(pic)
                 # 指定存储桶名称和对象键
                 object_key = f'{uid}/{channel}/{d_push_time}_{index}.jpeg'
 
-                # 获取指定的存储桶
-                bucket = s3_resource.Bucket(bucket_name)
+                # OCI上传对象
+                oci.put_object(PUSH_BUCKET, object_key, image_data, 'image/jpeg')
+                # AWS获取指定的存储桶
+                # bucket = s3_resource.Bucket(bucket_name)
 
-                # 上传图像数据到 S3
-                bucket.put_object(Key=object_key, Body=image_data)
+                # AWS上传图像数据到 S3
+                # bucket.put_object(Key=object_key, Body=image_data)
             LOGGER.info(f'uid={uid},base64上传缩略图到S3成功')
         except Exception as e:
-            LOGGER.info('***upload_image_to_s3,uid={},errLine:{}, errMsg:{}'
-                        .format(uid, e.__traceback__.tb_lineno, repr(e)))
+            LOGGER.error('***upload_image_to_s3,uid={},errLine:{}, errMsg:{}'
+                         .format(uid, e.__traceback__.tb_lineno, repr(e)))
 
     @staticmethod
     def bird_recognition_demo(resultRsp):

+ 1 - 0
requirements.txt

@@ -96,3 +96,4 @@ uritemplate==4.1.1
 urllib3==1.26.0
 wcwidth==0.2.13
 zipp==3.18.1
+oci~=2.125.2