ProcessAndNotifySummary.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. using OASystem.API.OAMethodLib.DeepSeekAPI;
  2. using OASystem.API.OAMethodLib.Hotmail;
  3. using OASystem.API.OAMethodLib.JuHeAPI;
  4. using OASystem.API.OAMethodLib.QiYeWeChatAPI;
  5. using OASystem.Domain.ViewModels.QiYeWeChat;
  6. using System.Text.Json;
  7. using System.Text.Json.Serialization;
  8. using System.Web;
  9. using static OASystem.API.OAMethodLib.Hotmail.HotmailService;
  10. namespace OASystem.API.OAMethodLib.Quartz.Business
  11. {
  12. /// <summary>
  13. /// 获取hotmail邮件,自动总结邮件内容发送至企业微信邮件
  14. /// </summary>
  15. public static class ProcessAndNotifySummary
  16. {
  17. private static readonly SqlSugarClient _sqlSugar = AutofacIocManager.Instance.GetService<SqlSugarClient>();
  18. private static readonly IQiYeWeChatApiService _qiYeWeChatApiService = AutofacIocManager.Instance.GetService<IQiYeWeChatApiService>();
  19. private static readonly HotmailService _hotmailService = AutofacIocManager.Instance.GetService<HotmailService>();
  20. private static readonly IDeepSeekService _deepSeekService = AutofacIocManager.Instance.GetService<IDeepSeekService>();
  21. private static readonly Microsoft.Extensions.Logging.ILogger _logger =AutofacIocManager.Instance.GetService<ILoggerFactory>().CreateLogger("ProcessAndNotifySummary");
  22. /// <summary>
  23. /// hotmail 邮件 汇总 发送企微邮件
  24. /// 时间范围 昨天
  25. /// </summary>
  26. public static async void ProcessAndNotifySummaryAsync()
  27. {
  28. _logger.LogInformation("Hotmail 定时发送邮件 -> 开始");
  29. var hotmailConfigs = await _hotmailService.GetUserMailConfigListAsync(_sqlSugar);
  30. if (hotmailConfigs == null || !hotmailConfigs.Any()) return;
  31. _logger.LogInformation("Hotmail 定时发送邮件 -> 获取基础配置");
  32. var hotmails = hotmailConfigs.Select(x => x.UserName).ToList();
  33. var userIds = hotmailConfigs.Select(x => x.UserId).ToList();
  34. var cstZone = CommonFun.GetCstZone();
  35. var nowInCst = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, cstZone);
  36. var yesterdayStart = nowInCst.Date.AddDays(-1);
  37. var yesterdayEnd = yesterdayStart.AddDays(1).AddTicks(-1);
  38. _logger.LogInformation("Hotmail 定时发送邮件 -> 获取Hotmail邮件信息 -> 开始");
  39. // 获取邮件信息
  40. var emailInfos = await _hotmailService.GetMergedMessagesAsync(hotmails, yesterdayStart, yesterdayEnd);
  41. _logger.LogInformation("Hotmail 定时发送邮件 -> 获取Hotmail邮件信息 -> 结束");
  42. // 处理无邮件情况
  43. if (emailInfos == null || !emailInfos.Any())
  44. {
  45. _logger.LogInformation("Hotmail 定时发送邮件 -> 获取Hotmail邮件信息 -> 发送无邮件情况");
  46. await NotifyEmptyEmails(userIds);
  47. return;
  48. }
  49. //// 预处理:限制每封邮件正文长度,防止 Token 溢出
  50. //foreach (var mail in emailInfos)
  51. //{
  52. // mail.Content = CleanHtmlToPlainText(mail.Content);
  53. //}
  54. _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 开始");
  55. // 调用 AI
  56. var question = BuildMailSummaryPrompt(emailInfos);
  57. var res = await _deepSeekService.ChatAsync(question);
  58. if (res.Success)
  59. {
  60. _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 分析成功");
  61. // 清洗 AI 可能带出的 Markdown 格式符
  62. string cleanJson = res.Answer.Trim();
  63. if (cleanJson.StartsWith("```json")) cleanJson = cleanJson.Replace("```json", "").Replace("```", "").Trim();
  64. try
  65. {
  66. _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 解析AI返回的json -> 开始");
  67. var aiSummaryResults = JsonConvert.DeserializeObject<List<AiSummaryResult>>(cleanJson);
  68. var users = await _sqlSugar.Queryable<Sys_Users>().Where(x => x.IsDel == 0 && userIds.Contains(x.Id)).Select(x => new { x.Id, x.Email }).ToListAsync();
  69. foreach (var hotmailConfig in hotmailConfigs)
  70. {
  71. var qwEmail = users.FirstOrDefault(x => x.Id == hotmailConfig.UserId)?.Email;
  72. if (string.IsNullOrEmpty(qwEmail)) continue;
  73. if (hotmailConfig.UserName.Equals("925554512@qq.com") || hotmailConfig.UserName.Equals("Roy.Lei.Atom@hotmail.com"))
  74. {
  75. if (aiSummaryResults.Any(x => x.Recipient.Equals("925554512@qq.com")))
  76. {
  77. hotmailConfig.UserName = "925554512@qq.com";
  78. }
  79. if (aiSummaryResults.Any(x => x.Recipient.Equals("Roy.Lei.Atom@hotmail.com")))
  80. {
  81. hotmailConfig.UserName = "Roy.Lei.Atom@hotmail.com";
  82. }
  83. }
  84. // 获取 AI 为该账号生成的摘要
  85. var summary = aiSummaryResults?.FirstOrDefault(x => x.Recipient.Equals(hotmailConfig.UserName, StringComparison.OrdinalIgnoreCase));
  86. string finalSubject = $"{DateTime.Now:yyyy-MM-dd} - 邮件汇总";
  87. string finalBody = $"Hotmail账号 {hotmailConfig.UserName} 在 {yesterdayStart:yyyy-MM-dd HH:mm:ss} 至 {yesterdayEnd:yyyy-MM-dd HH:mm:ss} 时间段内,未查询到收件箱邮件信息。";
  88. if (summary != null)
  89. {
  90. finalSubject = $"[AI汇总] {summary.EmailSubject}";
  91. finalBody = summary.TextBody;
  92. }
  93. // 测试阶段默认发送在我的邮箱
  94. string defualtEmail1 = "johnny.yang@pan-american-intl.com";
  95. string defualtEmail2 = "Roy.lei@pan-american-intl.com";
  96. _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 解析AI返回的json -> 发送腾讯邮件 -> {email} 开始", qwEmail);
  97. var seedRes = await _qiYeWeChatApiService.EmailSendAsync(new EmailRequestDto
  98. {
  99. ToEmails = new List<string> {
  100. qwEmail,
  101. defualtEmail1,
  102. defualtEmail2
  103. },
  104. Subject = finalSubject,
  105. Body = finalBody,
  106. });
  107. if (seedRes.errcode == 0)
  108. {
  109. _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 解析AI返回的json -> 发送腾讯邮件 -> {email} 发送成功", qwEmail);
  110. }
  111. else
  112. {
  113. _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 解析AI返回的json -> 发送腾讯邮件 -> {email} 失败:【{ErrorMsg}】",
  114. qwEmail,seedRes.errmsg);
  115. }
  116. }
  117. }
  118. catch (Exception ex)
  119. {
  120. // 记录解析 JSON 失败日志
  121. _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 解析AI返回的json -> 失败:{ErrorMsg}", ex.Message);
  122. }
  123. }
  124. _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 分析成功");
  125. }
  126. /// <summary>
  127. /// 纯正则实现:剔除 HTML 标签、样式和脚本,保留核心文本
  128. /// </summary>
  129. private static string CleanHtmlToPlainText(string? html)
  130. {
  131. if (string.IsNullOrEmpty(html)) return string.Empty;
  132. // 1. 剔除脚本 (Script) 和 样式 (Style) 及其内部内容
  133. html = Regex.Replace(html, @"<(script|style)[^>]*?>.*?</\1>", "", RegexOptions.IgnoreCase | RegexOptions.Singleline);
  134. // 2. 剔除所有 HTML 标签
  135. html = Regex.Replace(html, @"<[^>]*>", " ");
  136. // 3. 将 HTML 实体字符转换回普通字符 (例如 &nbsp; -> 空格, &lt; -> <)
  137. html = HttpUtility.HtmlDecode(html);
  138. // 4. 清理多余的空白字符和重复换行
  139. html = Regex.Replace(html, @"\s+", " "); // 将多个空格/换行合并为一个空格
  140. html = Regex.Replace(html, @"(\n\s*){2,}", "\n"); // 压缩重复换行
  141. return html.Trim();
  142. }
  143. public static string BuildMailSummaryPrompt(List<MailDto> mailList)
  144. {
  145. var rawDataJson = System.Text.Json.JsonSerializer.Serialize(mailList, new JsonSerializerOptions { WriteIndented = false });
  146. return $@"
  147. # Role: .NET 邮件情报分析引擎 (JSON-ONLY Mode)
  148. ## Task
  149. 解析以下 `rawDataJson` 数据,按 `Recipient` (收件人) 分组并生成深度分析简报。
  150. ## Constraints (Strict)
  151. 1. **Output Format**: 只输出标准的 JSON 数组代码块。严禁包含任何开场白、结尾问候、Markdown 解释文字或非 JSON 字符。
  152. 2. **HTML Rule**: `TextBody` 字段内仅允许使用 `<strong>` 和 `<br />`。严禁使用 `\n`、`<div>` 或其他标签。
  153. 3. **Naming Convention**:
  154. - 字典 Key/属性名: 必须使用 **PascalCase** (如: Recipient, EmailSubject, TextBody)。
  155. - 内部逻辑变量: 使用 **camelCase**。
  156. 4. **Logic**:
  157. - 按请求中的 `to` 字段进行分组。
  158. - 分析每组邮件的业务关联性,生成 [当日概览]、[详情摘要]、[分析结论]。
  159. ## Output Schema
  160. [
  161. {{
  162. ""Recipient"": ""string"",
  163. ""EmailSubject"": ""每日情报分析报告"",
  164. ""TextBody"": ""<strong>[收件人:...]</strong><br /><br /><strong>[核心概览]</strong><br />...分析内容...<br /><br /><strong>[分析结论]</strong><br />...""
  165. }}
  166. ]
  167. ## Input Data
  168. {rawDataJson}
  169. ## Execution
  170. Now, output the JSON array based on the logic above. No prose, no chat, just the JSON block.";
  171. }
  172. private static async Task NotifyEmptyEmails(List<int> userIds)
  173. {
  174. var userEmails = await _sqlSugar.Queryable<Sys_Users>().Where(x => x.IsDel == 0 && userIds.Contains(x.Id)).Select(x => x.Email).ToListAsync();
  175. if (userEmails.Any())
  176. {
  177. await _qiYeWeChatApiService.EmailSendAsync(new EmailRequestDto
  178. {
  179. ToEmails = userEmails,
  180. Subject = $"{DateTime.Now:yyyy-MM-dd} - 邮件汇总",
  181. Body = "昨日暂未收到有效邮件。"
  182. });
  183. }
  184. }
  185. public class AiSummaryResult
  186. {
  187. public string Recipient { get; set; } = string.Empty;
  188. public string EmailSubject { get; set; } = string.Empty;
  189. public string TextBody { get; set; } = string.Empty;
  190. }
  191. }
  192. }