Commit d3b2bac2 authored by zhengjinlei's avatar zhengjinlei

增加客户画像

parent 4fd706a0
......@@ -4,3 +4,5 @@ from .toolapi import ToolsApi
from .tasksapi import TasksApi
from .dataapi import DataApi
from .agencyapi import AgencyApi
from .profileapi import ProfileApi
from .openapi import OpenApi
# coding: utf-8
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.request import Request
from rest_framework.response import Response
from inspect_report import permissions
from inspect_report.models import CustomProfile
import json
import logging
logger = logging.getLogger(__name__)
class OpenApi(viewsets.ViewSet):
authentication_classes = ()
permission_classes = (permissions.ValidateToken, )
# permission_classes = ()
@action(['get'], detail=False)
def labels(self, req: Request):
phone_num = req.GET.get('phone_num')
if not phone_num:
logger.error('[phone_label]---invalid params')
return Response({'code': -1, 'msg': '请传入手机号'})
labels = []
profile = CustomProfile.objects.filter(phone_number=phone_num).first()
if not profile:
return Response({'code': 0, 'msg': '查询成功', 'data': json.dumps(labels)})
if profile.custom_labels:
labels = profile.custom_labels.split('、')
return Response({'code': 0, 'msg': '查询成功', 'data': labels})
# coding: utf-8
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.request import Request
from rest_framework.response import Response
from before_request import before_request
from config.config import name_list
from inspect_report.models import CustomProfile
import logging
logger = logging.getLogger(__name__)
class ProfileApi(viewsets.ViewSet):
authentication_classes = ()
permission_classes = ()
@action(['get'], detail=False)
@before_request
def labels(self, req: Request):
page = req.GET.get('page', '1')
page_size = req.GET.get('page_size', '10')
region = req.GET.get('region', '')
username = req.data.get('username', '')
if username in name_list:
logger.info('[profile_labels]获取的username是: %s', username)
region = username
condition = {}
if region:
condition['region'] = region
profiles = CustomProfile.objects.filter(**condition).values('phone_number', 'region', 'call_recent',
'call_count', 'custom_labels')
paginator = Paginator(profiles, page_size)
total_count = paginator.count
try:
objects = paginator.page(page)
except PageNotAnInteger:
objects = paginator.page(1)
except EmptyPage:
objects = paginator.page(paginator.num_pages)
return Response({'code': 0, 'msg': '查询成功', 'total': total_count, 'data': objects.object_list})
# coding: utf-8
from inspect_report.models import Tasks, CheckSession, RulesStat, SeatStat, ScoreStat, Team, Seat
from inspect_report.models import Tasks, CheckSession, RulesStat
from config.config import TABLE_PRE
import json
import logging
import kronos
from datetime import datetime, timedelta
from inspect_report.utils.report_utils import single_rules_stat, single_seat_stat, single_score_stat
from inspect_report.utils.report_utils import single_rules_stat, single_seat_stat, single_score_stat, single_data_stat
"""定时任务
......@@ -15,7 +15,7 @@ from inspect_report.utils.report_utils import single_rules_stat, single_seat_sta
logger = logging.getLogger('app_file')
@kronos.register('30 6 * * *')
# @kronos.register('30 6 * * *')
def rule_stat(date_str=None):
"""
首页概述-违规项统计
......@@ -39,7 +39,7 @@ def rule_stat(date_str=None):
logger.info('[rule_stat]rule stat end.')
@kronos.register('30 6 * * *')
# @kronos.register('30 6 * * *')
def seat_stat(date_str=None):
"""
首页概述-违规坐席统计
......@@ -58,7 +58,7 @@ def seat_stat(date_str=None):
logger.info('[seat_stat]violate seat stat end.')
@kronos.register('30 6 * * *')
# @kronos.register('30 6 * * *')
def score_stat(date_str=None):
"""
坐席得分统计
......@@ -77,6 +77,25 @@ def score_stat(date_str=None):
logger.info('[score_stat]seat score stat end.')
@kronos.register('30 6 * * *')
def data_stat(date_str=None):
"""
坐席得分统计
:return:
"""
if not date_str:
date_str = datetime.now().strftime('%Y-%m-%d')
create_date = date_str
logger.info('[data_stat]data stat start...')
task_condition = {'hasCheck': 1, 'name__endswith': date_str}
tasks = Tasks.objects.filter(**task_condition).values('id', 'name', 'sessionCollectionId', 'extra')
stat_count = 0
for t in tasks:
single_data_stat(t, create_date, stat_count)
logger.info('[data_stat]seat count: [%s]', stat_count)
logger.info('[data_stat]seat score stat end.')
def seat_time_stat(start_date=None, end_date=None):
"""
首页概述-违规坐席统计
......
......@@ -246,6 +246,45 @@ class ScoreTemplate(models.Model):
db_table = 'score_template'
class CustomProfile(models.Model):
"""客户画像"""
name = models.CharField('客户姓名', max_length=190, null=True, blank=True)
phone_number = models.CharField('客户手机号', max_length=20, null=True, blank=True)
call_recent = models.DateTimeField('最近通话日期', null=True, blank=True)
call_count = models.IntegerField('通话次数', default=0)
custom_labels = models.CharField('客户标签', max_length=2000, null=True, blank=True)
region = models.CharField('所属地市', max_length=100, null=True, blank=True)
create_at = models.DateTimeField('创建时间', blank=True, null=True)
update_at = models.DateTimeField('更新时间', blank=True, null=True)
def __str__(self):
return self.phone_number
class Meta:
db_table = 'custom_profile'
class CustomLabel(models.Model):
"""客户标签"""
profile_id = models.IntegerField('客户画像主键', null=True, blank=True)
call_time = models.DateTimeField('通话日期', null=True, blank=True)
label = models.CharField('客户标签', max_length=100, null=True, blank=True)
team = models.CharField('呼叫团队', null=True, max_length=100)
agent_name = models.CharField('坐席名称', null=True, max_length=64)
task_id = models.IntegerField('质检任务标识')
session_id = models.CharField('会话唯一标识', max_length=64)
session_table_id = models.IntegerField('会话主键')
session_collection_id = models.CharField('所在表', null=True, max_length=32)
create_at = models.DateTimeField('创建时间', blank=True, null=True)
update_at = models.DateTimeField('更新时间', blank=True, null=True)
def __str__(self):
return self.label
class Meta:
db_table = 'custom_label'
class Round(Func):
function = 'ROUND'
arity = 2
......@@ -2,6 +2,7 @@
import logging
from rest_framework.permissions import BasePermission
from rest_framework.authentication import exceptions
from config.config import CUSTOM_PROFILE_TOKEN
log = logging.getLogger(__name__)
......@@ -10,17 +11,18 @@ class ValidateToken(BasePermission):
""" token 正确才可以调用 """
def has_permission(self, request, view):
try:
http_auth = request.GET.get('token', '')
http_auth = request.META['HTTP_AUTHORIZATION']
if http_auth:
# token = http_auth.split(' ')[1]
# if http_auth.split(' ')[0] != 'Token':
# log.error('token 认证异常 | HTTP_WXAUTH 中缺少 Token')
# raise exceptions.AuthenticationFailed(detail={'code': -5, 'msg': 'token 认证异常'})
# key = request.session.get(token, None)
# if not key:
# log.error('token 认证异常 | Token不存在或者已过期')
# raise exceptions.AuthenticationFailed(detail={'code': -5, 'msg': '无效的token'})
return True
token = http_auth.split(' ')[1]
if http_auth.split(' ')[0] != 'Token':
log.error('token 认证异常 | HTTP_AUTHORIZATION 中缺少 Token')
raise exceptions.AuthenticationFailed(detail={'code': -5,
'msg': 'token认证异常,HTTP_AUTHORIZATION 中缺少 Token'})
if token == CUSTOM_PROFILE_TOKEN:
log.info('token 认证成功')
return True
else:
raise exceptions.AuthenticationFailed(detail={'code': -5, 'msg': 'token 认证异常'})
except KeyError as ke:
log.error('token 认证异常 | header中缺少HTTP_WXAUTH | 异常信息 : KeyError : %s', str(ke))
raise exceptions.AuthenticationFailed(detail={'code': -5, 'msg': 'token 认证异常'})
......
......@@ -16,7 +16,7 @@ Including another URLconf
from django.contrib import admin
from django.urls import path
from .api.tasksapi import rule, seat, group, score, check, city_score
from .views import stat_rules_every, stat_seats_every, stat_scores_every, stat_time_every
from .views import stat_rules_every, stat_seats_every, stat_scores_every, stat_time_every, stat_data_every
urlpatterns = [
# path('admin/', admin.site.urls),
......@@ -30,4 +30,5 @@ urlpatterns = [
path('inspect/stat/seat/', stat_seats_every),
path('inspect/stat/score/', stat_scores_every),
path('inspect/stat/time/', stat_time_every),
path('inspect/stat/data/', stat_data_every),
]
......@@ -23,7 +23,9 @@ router = routers.DefaultRouter()
router.register(r'tools', api.ToolsApi, base_name='tools')
router.register(r'tasks', api.TasksApi, base_name='tasks')
router.register(r'data', api.DataApi, base_name='data')
router.register(r'agency', api.AgencyApi, base_name='data')
router.register(r'profile', api.ProfileApi, base_name='profile')
router.register(r'agency', api.AgencyApi, base_name='agency')
router.register(r'custom', api.OpenApi, base_name='custom')
# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
......
......@@ -8,7 +8,8 @@ from datetime import datetime, timedelta
from django.db.models import Sum
from inspect_report.models import RulesStat, CheckSession, Team, Seat, SeatStat, ScoreStat, ScoreTemplate, ScoreItems
from inspect_report.models import RulesStat, CheckSession, Team, Seat, SeatStat, ScoreStat, ScoreTemplate, ScoreItems, \
CustomProfile, CustomLabel
from config.config import TABLE_PRE
logger = logging.getLogger('app_file')
......@@ -86,16 +87,19 @@ def single_rules_stat(t, create_date, stat_count=0):
remain = get_remain(check)
if 'isViolation' in d.keys() and d['isViolation'] and 'rule' in d.keys() and 'name' in d['rule'].keys():
name = d['rule']['name']
rule_obj = {'create_date': create_date, 'sessionCollectionId': t['sessionCollectionId'],
'rule': name, 'rule_num': 1,
'task': team_seat().get(check['agentName'], '未找到团队'),
'agentName': check['agentName'], 'customName': check['customName'],
'score': check['score'], 'remainTime': remain,
'taskId': check['taskId'], 'sessionId': check['sessionId'],
'session_table_id': check['id']}
rules_list.append(RulesStat(**rule_obj))
stat_count += 1
name = name.replace('【', '[').replace('】', ']')
if name and '[客户画像]' in name:
save_custom_profile(t, check, name)
else:
rule_obj = {'create_date': create_date, 'sessionCollectionId': t['sessionCollectionId'],
'rule': name, 'rule_num': 1,
'task': team_seat().get(check['agentName'], '未找到团队'),
'agentName': check['agentName'], 'customName': check['customName'],
'score': check['score'], 'remainTime': remain,
'taskId': check['taskId'], 'sessionId': check['sessionId'],
'session_table_id': check['id']}
rules_list.append(RulesStat(**rule_obj))
stat_count += 1
logger.info('rule stat num: [%s]', stat_count)
RulesStat.objects.bulk_create(rules_list)
......@@ -196,3 +200,165 @@ def delete_stat_by_task(task):
RulesStat.objects.filter(taskId=task.id).delete()
SeatStat.objects.filter(taskId=task.id).delete()
ScoreStat.objects.filter(taskId=task.id).delete()
def save_custom_profile(task, check, name):
label = name.replace('[客户画像]', '')
custom = check['customName'].split('&') if check['customName'] else []
region = task['name'].split('_')[0]
if custom:
custom_name = custom[0]
custom_phone = custom[-1]
profile = CustomProfile.objects.filter(phone_number=custom_phone).first()
team = '未找到团队'
# team = team_seat().get(check['agentName'], '未找到团队')
call_time = datetime.strptime(check['startTime'].replace('.0', ''), "%Y-%m-%d %H:%M:%S") if check['startTime'] \
else None
if profile:
if call_time:
profile.call_recent = call_time
profile.call_count += 1
if not profile.custom_labels:
profile.custom_labels = label
if label not in profile.custom_labels.split('、'):
profile.custom_labels += f'、{label}'
profile.save()
else:
profile = CustomProfile.objects.create(name=custom_name, phone_number=custom_phone,
call_recent=call_time,
call_count=1, custom_labels=label, region=region,
create_at=datetime.now(), update_at=datetime.now())
CustomLabel.objects.create(profile_id=profile.id, call_time=call_time,
label=label, team=team, agent_name=check['agentName'], task_id=check['taskId'],
session_id=check['sessionId'], session_table_id=check['id'],
session_collection_id=task['sessionCollectionId'], create_at=datetime.now(),
update_at=datetime.now())
def single_data_stat(t, create_date, stat_count=0):
rule_stat_flag = False
seat_stat_flag = False
score_stat_flag = False
if not RulesStat.objects.filter(taskId=t['id']).exists():
rule_stat_flag = True
if not SeatStat.objects.filter(taskId=t['id']).exists():
seat_stat_flag = True
if not ScoreStat.objects.filter(taskId=t['id']).exists():
score_stat_flag = True
if rule_stat_flag or seat_stat_flag or score_stat_flag:
table_name = TABLE_PRE + t['sessionCollectionId']
tn = CheckSession.set_table(table_name)
session_condition = {'taskId': t['id']}
checks = tn.objects.filter(**session_condition).values('id', 'checkResult', 'agentName', 'customName', 'score',
'remainTime', 'startTime', 'closeTime', 'taskId',
'sessionId', 'violationRuleCount', 'scoreItemRecord')
seat_dict = {}
seat_list = []
score_dict = {}
score_list = []
service_s, business_s, vz, score_item_service, score_item_business, score_item_zero = get_inspect_rule(t)
for check in checks:
stat_count += 1
validate_rule_count = 0
remain = get_remain(check)
result = check['checkResult']
# rule_stat
if result:
rules_list = []
data = json.loads(result)
for d in data:
if 'isViolation' in d.keys() and d['isViolation'] and 'rule' in d.keys() and 'name' in d['rule'].keys():
name = d['rule']['name']
name = name.replace('【', '[').replace('】', ']')
if name and '[客户画像]' in name:
if rule_stat_flag:
save_custom_profile(t, check, name)
else:
validate_rule_count += 1
if rule_stat_flag:
rule_obj = {'create_date': create_date, 'sessionCollectionId': t['sessionCollectionId'],
'rule': name, 'rule_num': 1,
'task': '未找到团队',
# 'task': team_seat().get(check['agentName'], '未找到团队'),
'agentName': check['agentName'], 'customName': check['customName'],
'score': check['score'], 'remainTime': remain,
'taskId': check['taskId'], 'sessionId': check['sessionId'],
'session_table_id': check['id']}
rules_list.append(RulesStat(**rule_obj))
if rule_stat_flag:
RulesStat.objects.bulk_create(rules_list)
logger.info('data stat num: check编号为:[%s]违规项统计完毕', check['id'])
# seat_stat
if seat_stat_flag:
if check['agentName'] in seat_dict.keys():
seat = seat_dict.get(check['agentName'])
seat['total_session'] += 1
seat['remainTime'] += remain
seat['validate_session'] += 1 if validate_rule_count > 0 else 0
else:
seat_dict[check['agentName']] = {'create_date': create_date, 'agentName': check['agentName'],
'taskId': check['taskId'],
'task': '未找到团队',
# 'task': team_seat().get(check['agentName'], '未找到团队'),
'sessionCollectionId': t['sessionCollectionId'],
'total_session': 1}
seat_dict[check['agentName']]['validate_session'] = 1 if validate_rule_count > 0 else 0
seat_dict[check['agentName']]['remainTime'] = remain
# score_stat
if score_stat_flag:
score_item = json.loads(check['scoreItemRecord'])
service_score = 35
business_score = 65
validate_zero = 0
for m in score_item:
if m['scoreItemId'] in score_item_service.keys():
service_score -= m['score'] if m['scoreType'] == 1 else -m['score']
if m['scoreItemId'] in score_item_business.keys():
business_score -= m['score'] if m['scoreType'] == 1 else -m['score']
if m['scoreItemId'] in score_item_zero.keys():
validate_zero += 1
if validate_zero > 0:
score = 0
else:
score = service_score + business_score
if check['agentName'] in score_dict.keys():
seat = score_dict.get(check['agentName'])
seat['total_session'] += 1
seat['validate_session'] += 1 if validate_rule_count > 0 else 0
seat['validate_num'] += validate_rule_count
seat['score'] += score
seat['service_score'] += service_score
seat['business_score'] += business_score
seat['validate_zero'] += validate_zero
else:
score_dict[check['agentName']] = {'create_date': create_date, 'agentName': check['agentName'],
'taskId': check['taskId'],
'task': '未找到团队',
# 'task': team_seat().get(check['agentName'], '未找到团队'),
'sessionCollectionId': t['sessionCollectionId'], 'total_session': 1,
'score': score, 'service_score': service_score,
'business_score': business_score, 'validate_zero': validate_zero}
score_dict[check['agentName']]['validate_session'] = 1 if validate_rule_count > 0 else 0
score_dict[check['agentName']]['validate_num'] = validate_rule_count
logger.info('data stat num: [%s]', stat_count)
if seat_stat_flag:
for k, v in seat_dict.items():
seat_obj = {'agentName': k}
seat_obj.update(v)
seat_list.append(SeatStat(**seat_obj))
SeatStat.objects.bulk_create(seat_list)
logger.info('data stat num: 任务编号为:[%s]坐席统计完毕', t['id'])
if score_stat_flag:
for k, v in score_dict.items():
score_obj = {'agentName': k, 'score': round(v.pop('score') / v['total_session'], 2),
'business_score': round(v.pop('business_score') / v['total_session'], 2),
'service_score': round(v.pop('service_score') / v['total_session'], 2)}
score_obj.update(v)
score_list.append(ScoreStat(**score_obj))
ScoreStat.objects.bulk_create(score_list)
logger.info('data stat num: 任务编号为:[%s]得分统计完毕', t['id'])
from datetime import datetime, timedelta
from .cron import rule_stat, seat_stat, score_stat, seat_time_stat
from .cron import rule_stat, seat_stat, score_stat, seat_time_stat, data_stat
from django.http.response import JsonResponse
from dateutil.rrule import rrule, DAILY
......@@ -41,6 +41,18 @@ def stat_scores_every(request):
return JsonResponse({'code': 0, 'msg': 'stat success'})
def stat_data_every(request):
start_date = request.GET.get('start_date')
end_date = request.GET.get('end_date')
s_date = datetime.strptime(start_date, '%Y-%m-%d')
e_date = datetime.strptime(end_date, '%Y-%m-%d')
seed_dt = list(rrule(DAILY, byweekday=[0, 1, 2, 3, 4, 5, 6], dtstart=s_date, until=e_date))
for date in seed_dt:
date_str = date.strftime('%Y-%m-%d')
data_stat(date_str)
return JsonResponse({'code': 0, 'msg': 'stat success'})
def stat_time_every(request):
start_date = request.GET.get('start_date')
end_date = request.GET.get('end_date')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment