Przeglądaj źródła

智能邮箱客服初版

chenshibin 4 lat temu
rodzic
commit
b0148c45a5

+ 172 - 0
Utils/NeteaseMail.py

@@ -0,0 +1,172 @@
+import email
+import imaplib
+import re
+import smtplib
+from email.header import  Header
+from email.mime.text import MIMEText
+from nntplib import decode_header
+from turtle import pd
+
+from boto3 import Session
+from imapclient import IMAPClient
+
+
+
+class NeteaseMail:
+
+    # 连接邮箱服务器并登录。
+    def loginEmail(self, imap_server, from_addr, password, imap_port, isssl=True):
+        '''第一部分:收件IMAP4********************************************'''
+        '''登录邮箱IMAP4=========================================================='''
+        email_server = None
+        #993  465
+        try:
+
+            email_server = IMAPClient(imap_server, ssl=isssl, port=imap_port)
+            #email_server = imaplib.IMAP4_SSL(IMAP_SERVER, 993)  # 网易企业邮箱服务器及SSL端口
+            print("imap4 服务器连接成功")
+
+            email_server.login(from_addr, password)
+
+            email_server.id_({"name": "IMAPClient", "version": "2.1.0"})
+            #email_server.login(FROM_ADDR, PASSWORD)
+            print("imap4 账号密码正确,登录成功")
+        except:
+            print("imap4 服务器连接失败")
+        else:
+            return email_server
+
+    #关闭邮箱服务器连接
+    def closeEmail(self, email_server):
+        # 关闭select
+        email_server.close()
+        # 关闭连接
+        email_server.logout()
+
+    #获取邮箱内容、标题、发件人
+    def getEmailContext(self, email_server):
+        ''' 邮箱中收到的未读邮件的数量=========================================================='''
+        #email_server.select_folder('INBOX', readonly=True)
+
+        email_server.select_folder('INBOX', readonly=True)  # readonly=True表明只读并不修改任何信息
+        results = email_server.search()
+        subject_list = []
+        bodydata_list = []
+        from_list = []
+        try:
+            for uid in results:
+                msgdict = email_server.fetch(uid, ['Body[]','ENVELOPE'], '(RFC822)')
+                mailbody = msgdict[uid][b'BODY[]']
+                envelope = msgdict[uid][b'ENVELOPE']
+                message = email.message_from_bytes(mailbody)
+
+                msgfrom = message['from']
+                m_type = message.get('Content-Type')
+                if m_type and 'text/html' in m_type:
+                    con3 = message.get_payload(decode=True).strip()
+                    subject = message['Subject']
+                    subdecode = decode_header(subject)
+                    subject_list.append(subdecode)
+                    from_list.append(message['from'])
+                    bodydata_list.append(con3.decode('utf8'))
+
+        except:
+           print('获取内容出错')
+        else:
+            return subject_list, from_list, bodydata_list
+        # if subject_list and bodydata_list:
+        #     data_unseen = [subject_list, bodydata_list]
+        #     data_unseen1 = pd.DataFrame(data_unseen)
+        #     data_unseen1.to_csv('data_unseen.csv', sep=',', header=True, index=True, encoding='utf_8_sig')
+        #
+        #     aws_key = "ASIA2E67UIMDTJFRF7UE"  # 【你的 aws_access_key】
+        #     aws_secret = "5u6MDvm3Fabdbc6EG9+JPJE3x07peNkrvok76Dqq"  # 【你的 aws_secret_key】
+        #     aws_session_token = "FwoGZXIvYXdzEHQaDKQchZxanXOpNJ2UriLoARUmKF/Uf6HZMhB4Bdo1Df4BlirgpqOyXmMULjx1yvqah1+BKIV2rzEoxxaVmvjcvLjHMQamPR7QzLZYP/WgJ6biPTnfqJWy5rCVpIZtD3D2nmGWAf5RSedADILJgBQmrXumFX2jrnm6THbqfdyfT2eitKt5ZD82zvLOaHMWu7mzomzmye8Eimt28Dhj6jsLeZPxOhhHBLUi+gddHAMCQq8HmGbnsXN5OrOBvqreRAxdR/u6vuQHbVpV3b8V5nkAtTVhOCaGRcPETARB8F/jFuFRhW9tAjPZisP/SEa8vUDR32FoMNQeda4o5+7l/gUyKYlem5bIB96gywY6s4C8c1PAa3l09+5tdGNp5laAJf7vMUzMJckR2EgF"
+        #     session = Session(aws_access_key_id=aws_key,
+        #                       aws_secret_access_key=aws_secret,
+        #                       aws_session_token=aws_session_token,
+        #                       region_name="ap-southeast-1")  # 此处根据自己的 s3 地区位置改变
+        #     s3 = session.resource("s3")
+        #     client = session.client("s3")
+        #     bucket = "asj-oct-ipc"  # 【你 bucket 的名字】 # 首先需要保.证 s3 上已经存在该存储桶,否则报错
+        #     upload_data = open("./././static/log/error.log", "rb")
+        #     upload_key = "86YC8Z192VB1VMKU111A/vod1/test"
+        #     file_obj = s3.Bucket(bucket).put_object(Key=upload_key, Body=upload_data)
+
+
+    #发送邮箱
+    def faEmail(self,email_server,message,subject,from_addr,to_addr):
+        if email_server:
+            print("邮件开始发送")
+
+            message = message
+            msg = MIMEText(message, 'plain', 'utf-8')
+            msg['Subject'] = Header(subject, 'utf-8')
+            msg['From'] = Header(from_addr)
+
+        try:
+            msg['To'] = Header(to_addr, 'utf-8')
+            email_server.sendmail(from_addr, to_addr, msg.as_string())  # 将msg转化成string发出
+            print("邮件发送成功")
+
+        except Exception as e:
+            print('Error:', e)
+
+        email_server.quit()
+
+    # def sentemail(self,message,subject,from_addr,to_addr):
+    #     host = 'smtp.163.com'
+    #     # 设置发件服务器地址
+    #     port = 465
+    #     # 设置发件服务器端口号。注意,这里有SSL和非SSL两种形式,现在一般是SSL方式
+    #     sender = FROM_ADDR
+    #     # 设置发件邮箱,一定要自己注册的邮箱
+    #     pwd = PASSWORD
+    #     # 设置发件邮箱的授权码密码,根据163邮箱提示,登录第三方邮件客户端需要授权码
+    #     receiver = to_addr
+    #     # 设置邮件接收人,可以是QQ邮箱
+    #     body = message
+    #     # 设置邮件正文,这里是支持HTML的
+    #     msg = MIMEText(body, 'html')
+    #     # 设置正文为符合邮件格式的HTML内容
+    #     msg['subject'] = subject
+    #     # 设置邮件标题
+    #     msg['from'] = from_addr
+    #     # 设置发送人
+    #     msg['to'] = to_addr
+    #     # 设置接收人
+    #     try:
+    #         s = smtplib.SMTP_SSL(host, port)
+    #         # 注意!如果是使用SSL端口,这里就要改为SMTP_SSL
+    #         s.login(sender, pwd)
+    #         # 登陆邮箱
+    #         s.sendmail(sender, receiver, msg.as_string())
+    #         # 发送邮件!
+    #         print('Done.sent email success')
+    #     except smtplib.SMTPException:
+    #         print('Error.sent email fail')
+
+    # mailto_list = ['xxxxxx@xx.com]
+    #                mail_host = "smtp.163.com"
+    # mail_user = "xxxxxx"
+    # mail_pass = "xxxxxxxxxx"
+    #
+    # def send_mail(mailto_list, sub, content,mail_user,mail_pass):
+    #     me = "hello" + "<" + mail_user + "@1368035>"
+    #     msg = MIMEText(content, _subtype='plain')
+    #     msg['Subject'] = sub
+    #     msg['From'] = me
+    #     try:
+    #         for mail in mailto_list:
+    #             msg['To'] = mail
+    #             server = smtplib.SMTP()
+    #             server.connect(mail_host)
+    #             server.login(mail_user, mail_pass)
+    #             server.sendmail(me, mail, msg.as_string())
+    #             server.close()
+    #             del msg['To']
+    #         return True
+    #     except Exception, e:
+    #         print
+    #         str(e)
+    #         return False

+ 141 - 0
controller/ComprehendController.py

@@ -0,0 +1,141 @@
+import boto3
+from boto3 import Session
+from django.views import View
+
+
+from model.models import EmailSortModel, EmailConfigModel
+from Utils.NeteaseMail import NeteaseMail
+from django.views.generic import TemplateView
+
+from object.ResponseObject import ResponseObject
+
+
+class ComprehendView(TemplateView):
+
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)
+
+    def validation(self, request_dict, request, operation):
+        response = ResponseObject()
+        if operation is None:
+            return response.json(444, 'error path')
+        else:
+            if operation == 'createSort':
+                return self.createSort(request_dict, response)
+            elif operation == 'doStartSortWord':
+                return self.doStartSortWord(request_dict, response)
+            elif operation == 'getDocumentClassifier':
+                return self.get_document_classifier(request_dict, response)
+
+    def createSort(self,request_dict, response):
+        client = boto3.client('comprehend', region_name='region')
+
+        # Create a document classifier
+        create_response = client.create_document_classifier(
+            InputDataConfig={
+                'S3Uri': 's3://S3Bucket/docclass/file name'
+            },
+            DataAccessRoleArn='arn:aws:iam::account number:role/resource name',
+            DocumentClassifierName='SampleCodeClassifier1',
+            LanguageCode='en'
+        )
+        print("Create response: %s\n", create_response)
+
+        # Check the status of the classifier
+        describe_response = client.describe_document_classifier(
+            DocumentClassifierArn=create_response['DocumentClassifierArn'])
+        print("Describe response: %s\n", describe_response)
+
+        # List all classifiers in account
+        list_response = client.list_document_classifiers()
+        print("List response: %s\n", list_response)
+
+
+    def doStartSortWord(self,request_dict, response):
+        client = boto3.client('comprehend', region_name='region')
+
+        start_response = client.start_document_classification_job(
+            InputDataConfig={
+                'S3Uri': 's3://srikad-us-west-2-input/docclass/file name',
+                'InputFormat': 'ONE_DOC_PER_LINE'
+            },
+            OutputDataConfig={
+                'S3Uri': 's3://S3Bucket/output'
+            },
+            DataAccessRoleArn='arn:aws:iam::account number:role/resource name',
+            DocumentClassifierArn=
+            'arn:aws:comprehend:region:account number:document-classifier/SampleCodeClassifier1'
+        )
+
+        print("Start response: %s\n", start_response)
+
+        # Check the status of the job
+        describe_response = client.describe_document_classification_job(JobId=start_response['JobId'])
+        print("Describe response: %s\n", describe_response)
+
+        # List all classification jobs in account
+        list_response = client.list_document_classification_jobs()
+        print("List response: %s\n", list_response)
+
+
+    def  get_document_classifier(self,request_dict, response):
+        # aws_key = "AKIA2E67UIMD45Y3HL53"  # 【你的 aws_access_key】
+        # aws_secret = "ckYLg4Lo9ZXJIcJEAKkzf2rWvs8Xth1FCjqiAqUw"  # 【你的 aws_secret_key】
+        # session = Session(aws_access_key_id=aws_key,
+        #                   aws_secret_access_key=aws_secret,
+        #                   region_name="us-east-1")  # 此处根据自己的 s3 地区位置改变
+        # client = session.client("asj-amazon-comprehend")
+        # client = boto3.client(
+        #     'asj-amazon-comprehend',
+        #     aws_access_key_id='AKIA2E67UIMD45Y3HL53',
+        #     aws_secret_access_key='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',
+        #     region_name='us-east-1'
+        # )
+        #client = boto3.client(service_name='comprehend',region_name='us-east-1',aws_access_key_id='AKIA2E67UIMD45Y3HL53',aws_secret_access_key='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')
+
+        # response = client.describe_document_classifier(
+        #     DocumentClassifierArn='arn:aws:comprehend:us-east-1:697864307463:document-classifier/txttwo'
+        # )
+        # print(response)
+        ec_qs =EmailConfigModel.objects.filter(emailtag=1) #获取总邮件
+
+        for ec in ec_qs:
+
+            email_server = NeteaseMail().loginEmail(ec['emailserver'], ec['fromaddr'], ec['password'], ec['emailserverport'])
+            subject_list, from_list, bodydata_list = NeteaseMail().getEmailContext(email_server)
+            NeteaseMail().closeEmail(email_server)
+
+            for i ,v in enumerate(subject_list):
+
+                client = boto3.client('comprehend')
+                response = client.classify_document(
+                    Text=bodydata_list[i],
+                    EndpointArn='arn:aws:comprehend:us-east-1:697864307463:document-classifier-endpoint/test'
+                )
+                #print(response.index(max(response['Classes']['Score'])))
+                nums = []
+                for cls in response['Classes']:
+                    print(cls['Name'])
+                    nums.append(cls['Score'])
+
+                print(response['Classes'][nums.index(max(nums))])
+
+                es_qs = EmailSortModel.objects.filter(sort=response['Classes'][nums.index(max(nums))]['Name'])
+                if es_qs.exists():
+                    uemail_qs = EmailConfigModel.objects.filter(userid=es_qs[0]['userid'], langconfig__langcode='en')
+                    if uemail_qs.exists():
+                        for uem in uemail_qs:
+                            NeteaseMail().sentemail(bodydata_list[i], subject_list[i], from_list[i], uem.fromaddr)
+
+        return response.json(0)
+        #print(response)
+
+# if __name__ == '__main__':
+#     ComprehendAction().get_document_classifier()

+ 24 - 0
controller/EmailProjectController.py

@@ -0,0 +1,24 @@
+import boto3
+from boto3 import Session
+from django.views import View
+
+
+from model.models import EmailSortModel, EmailConfigModel
+from Utils.NeteaseMail import NeteaseMail
+from django.views.generic import TemplateView
+
+from object.ResponseObject import ResponseObject
+
+
+class EmailProjectView(TemplateView):
+
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)
+

+ 23 - 0
controller/EmailSortController.py

@@ -0,0 +1,23 @@
+import boto3
+from boto3 import Session
+from django.views import View
+
+
+from model.models import EmailSortModel, EmailConfigModel
+from Utils.NeteaseMail import NeteaseMail
+from django.views.generic import TemplateView
+
+from object.ResponseObject import ResponseObject
+
+
+class EmailSorView(TemplateView):
+
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)

+ 25 - 0
controller/EmailUserController.py

@@ -0,0 +1,25 @@
+import boto3
+from boto3 import Session
+from django.views import View
+
+
+from model.models import EmailSortModel, EmailConfigModel
+from Utils.NeteaseMail import NeteaseMail
+from django.views.generic import TemplateView
+
+from object.ResponseObject import ResponseObject
+
+
+class EmailUserView(TemplateView):
+
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)
+
+    

+ 24 - 0
controller/EmaillangController.py

@@ -0,0 +1,24 @@
+import boto3
+from boto3 import Session
+from django.views import View
+
+
+from model.models import EmailSortModel, EmailConfigModel
+from Utils.NeteaseMail import NeteaseMail
+from django.views.generic import TemplateView
+
+from object.ResponseObject import ResponseObject
+
+
+class EmaillangView(TemplateView):
+
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)
+

+ 4 - 2
langer/urls.py

@@ -1,7 +1,8 @@
 from django.contrib import admin
 from django.urls import path, re_path
 from controller import User, LangSet, LangWord, LangArea, WebHook, AsImg, SysSet, Lottery, SkuSuitName, \
-    SkuConditionName, SkuRuleName, EmailSend, LangAVSSController, LangProjectController, SearchToolController
+    SkuConditionName, SkuRuleName, EmailSend, LangAVSSController, LangProjectController, SearchToolController, \
+    ComprehendController
 
 urlpatterns = [
     path('admin/', admin.site.urls),
@@ -42,6 +43,7 @@ urlpatterns = [
     re_path('email_send/(?P<operation>.*)', EmailSend.EmailSendView.as_view()),
     re_path('avss/(?P<operation>.*)', LangAVSSController.LangAVSSView.as_view()),
     re_path('langProject/(?P<operation>.*)', LangProjectController.LangProjectView.as_view()),
-    re_path('searchtool/(?P<operation>.*)', SearchToolController.SearchToolView.as_view())
+    re_path('searchtool/(?P<operation>.*)', SearchToolController.SearchToolView.as_view()),
+    re_path('comprehend/(?P<operation>.*)', ComprehendController.ComprehendView.as_view())
 
 ]

+ 57 - 0
model/models.py

@@ -255,3 +255,60 @@ class SearchToolKeyModel(models.Model):
         verbose_name = 'key关联协议表'
         verbose_name_plural = verbose_name
         db_table = 'search_tool_block_key'
+
+'''  ------------------------------智能客服 start-------------------------------------------'''
+class EmailLangConfig(models.Model):
+    emaillangid = models.AutoField(primary_key=True, verbose_name=u'自增ID')
+    lang = models.CharField(max_length=32, verbose_name=u'语言')
+    langcode = models.CharField(max_length=32, verbose_name=u'语言编码')
+    langdescribe = models.CharField(max_length=64, verbose_name=u'语言描述')
+
+    class Meta:
+        db_table = 'langconfig'
+        verbose_name = u'语言配置'
+        verbose_name_plural = verbose_name
+
+
+class EmailSortModel(models.Model):
+    emailsortid = models.AutoField(primary_key=True, verbose_name=u'自增ID')
+    sort = models.CharField(max_length=200, default='', verbose_name='负责分类')
+    sortcode = models.CharField(max_length=200, default='', verbose_name='分类编号')
+    parentsortid = models.CharField(max_length=200, null=True, verbose_name='父节点分类')
+    isautoreply = models.SmallIntegerField(default=0, verbose_name='是否自动回复')  # 0:不自动回复 1:自动回复
+    autoreplymodel = models.TextField(blank=True, null=True, verbose_name=u'回复模板')
+    # iszhuanfa = models.SmallIntegerField(default=0, verbose_name='是否转发其同事处理')  # 0:不 1:是
+    # zhuanfauser = models.ForeignKey(UserInfo, to_field='userid', on_delete=models.CASCADE) # 转发用户ID
+
+    class Meta:
+        db_table = 'emailsort'
+        verbose_name = u'邮箱分类配置表'
+        verbose_name_plural = verbose_name
+
+class EmailProjectConfigModel(models.Model):
+    emailprojectid = models.AutoField(primary_key=True)
+    projecname = models.CharField(max_length=200, default='', verbose_name='项目名')
+    projeccode = models.CharField(max_length=200, default='', verbose_name='项目编号')
+
+    class Meta:
+        db_table = 'emailprojectconfig'
+        verbose_name = '邮箱项目配置表'
+        verbose_name_plural = verbose_name
+
+class EmailConfigModel(models.Model):
+    emailid = models.AutoField(primary_key=True)
+    fromaddr = models.CharField(max_length=200, default='', verbose_name='邮箱账号')
+    password = models.CharField(max_length=64, default='', verbose_name='客户端授权码')
+    emailservername = models.CharField(max_length=64, default='', verbose_name='邮箱服务器名称')
+    emailserver = models.CharField(max_length=64, default='', verbose_name='邮箱服务器地址')
+    emailserverport = models.IntegerField(default=0, verbose_name='邮箱服务器端口')
+    emailserverportagreement = models.CharField(max_length=64, default='', verbose_name='邮箱服务器协议')
+    emaillangconfig = models.ManyToManyField(to='EmailLangConfig', blank=True, verbose_name=u'邮箱负责语言', db_table='emaillang')
+    emailproject = models.ForeignKey(EmailProjectConfigModel, to_field='emailprojectid', on_delete=models.CASCADE, verbose_name='邮箱项目配置表')
+    emailsort = models.ForeignKey(EmailSortModel, to_field='emailsortid', on_delete=models.CASCADE, verbose_name='邮箱分类配置表')
+    emailtag = models.SmallIntegerField(default=0, verbose_name='邮箱标签')  # 0:个人 1:总部 2:其他
+    class Meta:
+        db_table = 'emailconfig'
+        verbose_name = '邮箱配置表'
+        verbose_name_plural = verbose_name
+
+'''  ------------------------------智能客服 end-------------------------------------------'''