SACenter/SA.Domain.XFYun/XFYunDomains/XFYunDomain.cs

591 lines
23 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Diagnostics;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Newtonsoft.Json;
namespace SA.Domain.XFYun.XFYunDomains
{
/// <summary>
/// 讯飞处理
/// </summary>
public class XFYunDomain : IXFYunDomain
{
private readonly SystemConfig _systemConfig;
private readonly IXFYunApi _xfyunApi;
private readonly IZXDApi _zxdApi;
/// <summary>
/// 讯飞处理
/// </summary>
/// <param name="xfyunApi"></param>
/// <param name="zxdApi"></param>
public XFYunDomain(
IXFYunApi xfyunApi,
IZXDApi zxdApi)
{
_xfyunApi = xfyunApi;
_zxdApi = zxdApi;
_systemConfig = InitConfiguration.GetSection("SystemConfig").Get<SystemConfig>();
}
/// <summary>
/// 发送信息
/// </summary>
/// <returns></returns>
public async Task SendSms()
{
try
{
var tasks = await InitDB.zxdcrmDb.Queryable<CsvrAiCalltask>()
.Where(x => x.Sms == 1 && x.Smstime <= DateTime.Now)
.ToListAsync();
if (tasks == null || !tasks.Any()) return;
var mobiles = tasks.Select(x => x.Resid).Distinct().ToList();
var request = new ZXDEntity.SmsMessage
{
Message = SerializeHelper.ToJson(new
{
_systemConfig.SmsConfig.TypeCode,
_systemConfig.SmsConfig.SubTypeCode,
Para = ""
}),
Mobile = mobiles
};
var taskIds = tasks.Select(x => x.Id).ToList();
var orders = await InitDB.zxdcrmDb.Queryable<WxSzzyorder>()
.LeftJoin<CsvrAiCalltaskOrders>((t1, t2) => t1.Orderid == t2.Orderid)
.Where((t1, t2) => taskIds.Contains(t2.Taskid.Value))
.ToListAsync();
// 判断订单是否已开通,如果已开通则不执行外呼
if (orders.Any(x => x.Orderstatus == "220" || x.AiHgrecordStatus == -1))
{
LogHelper.Info($"订单[{string.Join(",", orders.Select(x => x.Orderid).ToList())}]已忽略外呼,不执行[短信发送任务]");
tasks.ForEach(x =>
{
x.Sms = 2;
x.Smstime = DateTime.Now;
});
}
else
{
var result = await _zxdApi.PutSms(request);
if (result.Result)
{
tasks.ForEach(x =>
{
x.Sms = 2;
x.Smstime = DateTime.Now;
});
}
}
await InitDB.zxdcrmDb.Updateable(tasks).ExecuteCommandAsync();
}
catch (Exception ex)
{
LogHelper.Error(ex, "短信任务报错!");
}
}
/// <summary>
/// 订单外呼
/// </summary>
/// <returns></returns>
public async Task OrderOutbound()
{
try
{
var time = DateTime.Now.AddMinutes(_systemConfig.IntervalMinutes);
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
var key = "singleAdd";
var accessKey = _systemConfig.ClientKey.Where(x => x.Id == _systemConfig.CRMClientKey).Select(x => x.AccessKey).First();
List<int> userStatus = new List<int> { 8, 9 };
var list = await InitDB.zxdcrmDb.Queryable<CsvrAiCalltask>()
.LeftJoin<ResResourcemobile>((t1, t2) => t1.Resid == t2.Resid)
.Where(t1 =>
(t1.Sms == 0 || (t1.Sms == 2 && t1.Smstime <= time))
&& t1.Status == 0
&& t1.Exetime <= DateTime.Now
&& !userStatus.Contains(t1.AiHgrecordStatus.Value)) //排除人工操作的任务
.Select((t1, t2) => new SingleAddRequest
{
ExtTaskId = t1.Id.ToString(),
AppId = t1.AppId,
CallNo = t1.CallNo,
Priority = t1.Priority,
Robot = t1.Robot,
Phone = t2.Mobile,
PropsStr = t1.Props,
Ext = _systemConfig.Ext
})
.ToListAsync();
stopwatch.Stop();
LogHelper.Info($"订单外呼查询【{stopwatch.ElapsedMilliseconds}ms】");
if (list == null || !list.Any()) return;
var tasks = await InitDB.zxdcrmDb.Queryable<CsvrAiCalltask>()
.Where(x => list.Select(y => int.Parse(y.ExtTaskId ?? "0")).Contains(x.Id))
.ToListAsync();
var taskIds = tasks.Select(x => x.Id).ToList();
LogHelper.Info($"任务[{string.Join(",", taskIds)}]正在执行[外呼任务],任务数量[{taskIds.Count}]");
foreach (var param in list)
{
var task = tasks.First(x => x.Id.ToString() == param.ExtTaskId);
await CallOrder(param, task);
}
}
catch (Exception ex)
{
LogHelper.Error(ex, "定时任务报错!");
}
}
public async Task CallOrder(SingleAddRequest param, CsvrAiCalltask task)
{
var key = "singleAdd";
var accessKey = _systemConfig.ClientKey.Where(x => x.Id == _systemConfig.CRMClientKey).Select(x => x.AccessKey).First();
try
{
param.Phone = SecurityHelper.DecyptData(param.Phone, accessKey);
}
catch (Exception ex)
{
Log.Warning("手机号解密失败,尝试[gd_crm]进行解密" + ex.Message);
var ordAccessKey = _systemConfig.ClientKey.Where(x => x.Id == "gd_crm").Select(x => x.AccessKey).First();
try
{
param.Phone = SecurityHelper.DecyptData(param.Phone, ordAccessKey);
}
catch (Exception ex2)
{
LogHelper.Error("手机号解密失败!", ex2);
}
}
param.Props = string.IsNullOrEmpty(param.PropsStr) ? new Dictionary<string, string>() :
SerializeHelper.FromJson<Dictionary<string, string>>(param.PropsStr);
var orders = await InitDB.zxdcrmDb.Queryable<WxSzzyorder>()
.LeftJoin<CsvrAiCalltaskOrders>((t1, t2) => t1.Orderid == t2.Orderid)
.Where((t1, t2) => task.Id == t2.Taskid)
.ToListAsync();
// 生成唯一id
task.ExtTaskId = CreateExTaskId(task.Id);
param.ExtTaskId = task.ExtTaskId;
var request = new XFYunRequest<SingleAddRequest>(
param.AppId,
key,
_systemConfig.XFYunGroudId,
param);
List<int> containStatus = new List<int>
{
82243656,82243655,82243649,82243646,82243525,82243515,82243504,82243469,82243393,82243351,82243330,82243276,82243265,82243246,82242374,82243488,82244062
};
// 判断订单是否已开通,如果已开通则不执行外呼
if (orders.Any(x => x.Orderstatus == "220" || x.AiHgrecordStatus == -1))
{
LogHelper.Info($"订单[{string.Join(",", orders.Select(x => x.Orderid).ToList())}]已忽略外呼,不执行[外呼任务]");
task.Status = 2;
orders.ForEach(x => x.AiHgrecordStatus = -1);
}
else
{
// 执行外呼
var result = await _xfyunApi.SingleAdd(request);
task.Utime = DateTime.Now;
if (result.Ret == 0 && result.Data.Success)
{
task.Status = 1;
orders.ForEach(x => x.AiHgrecordStatus = 2);
}
else
{
task.Status = 2;
task.RetDesc = result.Ret != 0 ? result.Msg : result.Data.Desc;
orders.ForEach(x => x.AiHgrecordStatus = 4);
}
}
if (orders.Any(x => containStatus.Contains(x.Orderid)))
{
LogHelper.Info($"订单[{string.Join(",", orders.Select(x => x.Orderid).ToList())}]忽略订单状态,直接外呼");
var result = await _xfyunApi.SingleAdd(request);
task.Utime = DateTime.Now;
if (result.Ret == 0 && result.Data.Success)
{
task.Status = 1;
orders.ForEach(x => x.AiHgrecordStatus = 2);
}
else
{
task.Status = 2;
task.RetDesc = result.Ret != 0 ? result.Msg : result.Data.Desc;
orders.ForEach(x => x.AiHgrecordStatus = 4);
}
}
task.AiHgrecordStatus = orders.FirstOrDefault() == null ? task.AiHgrecordStatus : orders.FirstOrDefault()?.AiHgrecordStatus;
try
{
InitDB.zxdcrmDb.BeginTran();
await InitDB.zxdcrmDb.Updateable(orders).UpdateColumns(x => new
{
x.AiHgrecordStatus,
x.AiHgrecordStatusname
}).ExecuteCommandAsync();
await InitDB.zxdcrmDb.Updateable(task).ExecuteCommandAsync();
InitDB.zxdcrmDb.CommitTran();
}
catch (Exception ex)
{
InitDB.zxdcrmDb.RollbackTran();
LogHelper.Error(ex, "[外呼任务]报错!");
}
}
/// <summary>
/// 生成唯一id
/// </summary>
/// <param name="taksId"></param>
/// <returns></returns>
private static string CreateExTaskId(int taksId)
{
var unixTime = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
var randomString = CreateRandomNumber(4);
return $"{unixTime}{taksId}{randomString}";
}
/// <summary>
/// 生成随机数字
/// </summary>
/// <param name="Length">生成长度</param>
/// <param name="Sleep">是否要在生成前将当前线程阻止以避免重复</param>
/// <returns></returns>
private static string CreateRandomNumber(int Length, bool Sleep = true)
{
if (Sleep)
Thread.Sleep(3);
string result = "";
Random random = new();
for (int i = 0; i < Length; i++)
{
result += random.Next(10).ToString();
}
return result;
}
/// <summary>
/// 回调函数
/// </summary>
/// <param name="detail"></param>
/// <returns></returns>
public async Task<dynamic> Callback(CallDetail detail)
{
try
{
var task = await InitDB.zxdcrmDb.Queryable<CsvrAiCalltask>()
.Where(x => x.ExtTaskId == detail.ExtTaskId)
.OrderByDescending(x => x.Id)
.FirstAsync();
var orders = await InitDB.zxdcrmDb.Queryable<WxSzzyorder>()
.LeftJoin<CsvrAiCalltaskOrders>((t1, t2) => t1.Orderid == t2.Orderid)
.Where((t1, t2) => task.Id == t2.Taskid)
.ToListAsync();
// 不明文显示
//detail.Phone = SecurityHelper.EncyptData(detail.Phone, "UPWEBSITE");
LogHelper.Info($"讯飞回调刷新 {string.Join(",", orders.Select(n => n.Orderid))} 讯飞结果:{JsonConvert.SerializeObject(detail)}");
await UpdateTask(task, orders, detail, true);
}
catch (Exception ex)
{
LogHelper.Error(ex, "更新回调信息报错!");
}
return new
{
rc = "000000",
desc = ""
};
}
/// <summary>
/// 更新任务状态
/// </summary>
/// <param name="task"></param>
/// <param name="orders"></param>
/// <param name="detail"></param>
/// <param name="result"></param>
/// <param name="error"></param>
/// <returns></returns>
private static async Task UpdateTask(CsvrAiCalltask? task, List<WxSzzyorder> orders, CallDetail detail, bool result = false, string error = "")
{
if (task == null) return;
task.Status = 2;
task.Exetime = DateTime.Now;
task.CallRet = detail.CallRet;
task.Audio = detail.Audio;
task.Labels = detail.Labels;
task.Content = detail.Content;
task.EndTime = string.IsNullOrEmpty(detail.EndTime) ? null : DateTime.Parse(detail.EndTime);
task.StartTime = string.IsNullOrEmpty(detail.StartTime) ? null : DateTime.Parse(detail.StartTime);
task.PlatSingleTaskId = detail.PlatTaskId;
task.SvcTime = detail.SvcTime;
task.Interact = detail.Interact == null || !detail.Interact.Any() ? "" : SerializeHelper.ToJson(detail.Interact);
task.Rounds = detail.Interact == null || !detail.Interact.Any() ? 0 : detail.Interact.Where(n => n.Type == "1").Count();
// 判断对话信息是否完整
var full = false;
var labels = new Dictionary<string, string>();
orders.ForEach(x => x.Hasaiaudio = string.IsNullOrEmpty(task.Audio) ? 0 : 1);
//人工操作的不刷新状态
List<int> userStatus = new List<int>
{
8,9
};
orders = orders.Where(n => !userStatus.Contains(n.AiHgrecordStatus.Value)).ToList();
var updateStatus = 0;
if (!string.IsNullOrEmpty(detail.Labels))
{
labels = SerializeHelper.FromJson<Dictionary<string, string>>(detail.Labels);
if (labels.Any() && labels.TryGetValue("访问结果", out string? label) && label == "正常访问")
{
full = true;
}
}
if (result && detail.Status == 3 && full)
{
task.RetDesc = detail.RetDesc;
updateStatus = string.IsNullOrEmpty(detail.RetDesc) ? 4 :
detail.RetDesc == "外呼成功" ? 5 : 3;
}
else
{
task.RetDesc = !string.IsNullOrEmpty(error) ? error :
!string.IsNullOrEmpty(detail.RetDesc) ? detail.RetDesc :
"外呼失败";
if (detail.Interact == null || !detail.Interact.Any())
{
updateStatus = 4;
}
else
{
// 如果不存在人为回答需要把状态改为AI外呼失败挂断
if (!detail.Interact.Any(x => x.Type == "1"))
{
updateStatus = 7;
}
else
{
updateStatus = 3;
}
}
}
task.AiHgrecordStatus = updateStatus;
var genOrderCallConfig = GenOrderCall.GetConfig();
var ReCallMin = genOrderCallConfig.ReCallMins;
//找出是否存在其他任务
if (orders.Count > 0)
{
var taskids = InitDB.zxdcrmDb.Queryable<CsvrAiCalltaskOrders>().Where(d => d.Orderid == orders.FirstOrDefault().Orderid).Select(d => d.Taskid).ToList();
//如果 任务外呼 失败 且 大于重拨次数 直接刷为 ai重拨失败
List<int> failStatus = new List<int> { 3, 4, 7 };
if (taskids.Count > ReCallMin.Count && failStatus.Contains(updateStatus))
{
updateStatus = -2;
LogHelper.Info($"订单【{string.Join(",", orders.Select(n => n.Orderid))}】刷新状态为【AI重拨失败】");
}
orders.ForEach(x => x.AiHgrecordStatus = updateStatus);
}
LogHelper.Info($"任务编号【{task.Id}】订单为【{string.Join(",", orders.Select(n => n.Orderid))}】刷新状态为【{task.AiHgrecordStatusname}】");
try
{
InitDB.zxdcrmDb.BeginTran();
await InitDB.zxdcrmDb.Updateable(orders).UpdateColumns(x => new
{
x.AiHgrecordStatus,
x.AiHgrecordStatusname,
x.Hasaiaudio
}).ExecuteCommandAsync();
await InitDB.zxdcrmDb.Updateable(task).ExecuteCommandAsync();
InitDB.zxdcrmDb.CommitTran();
}
catch (Exception ex)
{
InitDB.zxdcrmDb.RollbackTran();
LogHelper.Error(ex, "定时任务报错!");
}
}
/// <summary>
/// 轮询获取结果
/// </summary>
/// <returns></returns>
public async Task UpdateCallbackResult()
{
try
{
var time = DateTime.Now.AddMinutes(_systemConfig.CallbackMinutes);
var key = "singleQuery";
var accessKey = _systemConfig.ClientKey.Where(x => x.Id == _systemConfig.CRMClientKey).Select(x => x.AccessKey).First();
var tasks = await InitDB.zxdcrmDb.Queryable<CsvrAiCalltask>()
.Where(t1 => t1.Status == 1 && t1.Utime <= time)
.ToListAsync();
if (tasks == null || !tasks.Any()) return;
foreach (var task in tasks)
{
if (task == null) continue;
var taskId = task?.Id;
var param = new SingleQueryRequest()
{
ExtTaskId = task?.ExtTaskId ?? task?.Id.ToString(),
AppId = task?.AppId,
};
var request = new XFYunRequest<SingleQueryRequest>(
param.AppId,
key,
_systemConfig.XFYunGroudId,
param);
// 获取结果
var result = await _xfyunApi.SingleQuery(request);
var orders = await InitDB.zxdcrmDb.Queryable<WxSzzyorder>()
.LeftJoin<CsvrAiCalltaskOrders>((t1, t2) => t1.Orderid == t2.Orderid)
.Where((t1, t2) => taskId == t2.Taskid)
.ToListAsync();
LogHelper.Info($"任务自动刷新时间,任务id: {taskId} {string.Join(",", orders.Select(n => n.Orderid))}讯飞结果:{JsonConvert.SerializeObject(result)}");
if (result.Ret == 0 && result?.Data?.Result != null)
{
//录音不为空才做更新
if (!string.IsNullOrWhiteSpace(result.Data.Result.Audio))
{
await UpdateTask(task, orders, result.Data.Result, result.Data.Success, result.Error ?? "");
}
}
else
{
LogHelper.Error($"定时任务获取结果出错任务id: {taskId}, 错误信息: {result?.Msg}");
}
}
}
catch (Exception ex)
{
LogHelper.Error(ex, "定时任务报错!");
}
}
/// <summary>
///
/// </summary>
/// <param name="taskId"></param>
/// <returns></returns>
public async Task<CsvrAiCalltask?> GetCallbackResult(int taskId)
{
try
{
var key = "singleQuery";
var task = await InitDB.zxdcrmDb.Queryable<CsvrAiCalltask>()
.Where(t1 => t1.Id == taskId)
.FirstAsync();
if (task == null) return task;
var param = new SingleQueryRequest()
{
ExtTaskId = task?.ExtTaskId ?? task?.Id.ToString(),
AppId = task?.AppId,
};
var request = new XFYunRequest<SingleQueryRequest>(
param.AppId,
key,
_systemConfig.XFYunGroudId,
param);
// 获取结果
var result = await _xfyunApi.SingleQuery(request);
var orders = await InitDB.zxdcrmDb.Queryable<WxSzzyorder>()
.LeftJoin<CsvrAiCalltaskOrders>((t1, t2) => t1.Orderid == t2.Orderid)
.Where((t1, t2) => taskId == t2.Taskid)
.ToListAsync();
if (result.Ret == 0 && result?.Data?.Result != null)
{
await UpdateTask(task, orders, result.Data.Result, result.Data.Success, result.Error ?? "");
}
else
{
LogHelper.Error($"定时任务获取结果出错任务id: {taskId}, 错误信息: {result?.Msg}");
}
return task;
}
catch (Exception ex)
{
LogHelper.Error(ex, "更新回调信息报错!");
return null;
}
}
/// <summary>
/// 单纯获取讯飞结果
/// </summary>
/// <param name="taskId"></param>
/// <returns></returns>
public async Task<string> GetCallbackResultByXunFei(int taskId)
{
try
{
var key = "singleQuery";
var task = await InitDB.zxdcrmDb.Queryable<CsvrAiCalltask>()
.Where(t1 => t1.Id == taskId)
.FirstAsync();
if (task == null) return "";
var param = new SingleQueryRequest()
{
ExtTaskId = task?.ExtTaskId ?? task?.Id.ToString(),
AppId = task?.AppId,
};
var request = new XFYunRequest<SingleQueryRequest>(
param.AppId,
key,
_systemConfig.XFYunGroudId,
param);
// 获取结果
var result = await _xfyunApi.SingleQuery(request);
var res = JsonConvert.SerializeObject(result);
return res.ToString();
}
catch (Exception ex)
{
LogHelper.Info($"获取讯飞结果出错{ex.Message}");
return $"获取讯飞结果出错{ex.Message}";
}
}
}
}