|
|
@@ -0,0 +1,186 @@
|
|
|
+using OASystem.API.OAMethodLib.DeepSeekAPI;
|
|
|
+using OASystem.API.OAMethodLib.Hotmail;
|
|
|
+using OASystem.API.OAMethodLib.QiYeWeChatAPI;
|
|
|
+using OASystem.Domain.ViewModels.QiYeWeChat;
|
|
|
+using System.Text.Json;
|
|
|
+using System.Text.Json.Serialization;
|
|
|
+using System.Web;
|
|
|
+using static OASystem.API.OAMethodLib.Hotmail.HotmailService;
|
|
|
+
|
|
|
+namespace OASystem.API.OAMethodLib.Quartz.Business
|
|
|
+{
|
|
|
+ /// <summary>
|
|
|
+ /// 获取hotmail邮件,自动总结邮件内容发送至企业微信邮件
|
|
|
+ /// </summary>
|
|
|
+ public static class ProcessAndNotifySummary
|
|
|
+ {
|
|
|
+ private static readonly SqlSugarClient _sqlSugar = AutofacIocManager.Instance.GetService<SqlSugarClient>();
|
|
|
+ private static readonly IQiYeWeChatApiService _qiYeWeChatApiService = AutofacIocManager.Instance.GetService<IQiYeWeChatApiService>();
|
|
|
+ private static readonly HotmailService _hotmailService = AutofacIocManager.Instance.GetService<HotmailService>();
|
|
|
+ private static readonly IDeepSeekService _deepSeekService = AutofacIocManager.Instance.GetService<IDeepSeekService>();
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// hotmail 邮件 汇总 发送企微邮件
|
|
|
+ /// 时间范围 昨天
|
|
|
+ /// </summary>
|
|
|
+ public static async void ProcessAndNotifySummaryAsync()
|
|
|
+ {
|
|
|
+ var hotmailConfigs = await _hotmailService.GetUserMailConfigListAsync();
|
|
|
+ if (hotmailConfigs == null || !hotmailConfigs.Any()) return;
|
|
|
+
|
|
|
+ var hotmails = hotmailConfigs.Select(x => x.UserName).ToList();
|
|
|
+ var userIds = hotmailConfigs.Select(x => x.UserId).ToList();
|
|
|
+
|
|
|
+ var cstZone = CommonFun.GetCstZone();
|
|
|
+ var nowInCst = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, cstZone);
|
|
|
+ var yesterdayStart = nowInCst.Date.AddDays(-1);
|
|
|
+ var yesterdayEnd = yesterdayStart.AddDays(3).AddTicks(-1);
|
|
|
+
|
|
|
+ var emailInfos = await _hotmailService.GetMergedMessagesAsync(hotmails, yesterdayStart, yesterdayEnd);
|
|
|
+
|
|
|
+ // 处理无邮件情况
|
|
|
+ if (emailInfos == null || !emailInfos.Any())
|
|
|
+ {
|
|
|
+ await NotifyEmptyEmails(userIds);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 预处理:限制每封邮件正文长度,防止 Token 溢出
|
|
|
+ foreach (var mail in emailInfos)
|
|
|
+ {
|
|
|
+ mail.Content = CleanHtmlToPlainText(mail.Content);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 调用 AI
|
|
|
+ var question = BuildMailSummaryPrompt(emailInfos);
|
|
|
+ var res = await _deepSeekService.ChatAsync(question);
|
|
|
+
|
|
|
+ if (res.Success)
|
|
|
+ {
|
|
|
+ // 清洗 AI 可能带出的 Markdown 格式符
|
|
|
+ string cleanJson = res.Answer.Trim();
|
|
|
+ if (cleanJson.StartsWith("```json")) cleanJson = cleanJson.Replace("```json", "").Replace("```", "").Trim();
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var aiSummaryResults = JsonConvert.DeserializeObject<List<AiSummaryResult>>(cleanJson);
|
|
|
+ var users = await _sqlSugar.Queryable<Sys_Users>().Where(x => x.IsDel == 0 && userIds.Contains(x.Id)).Select(x => new { x.Id, x.Email }).ToListAsync();
|
|
|
+
|
|
|
+ foreach (var hotmailConfig in hotmailConfigs)
|
|
|
+ {
|
|
|
+ var qwEmail = users.FirstOrDefault(x => x.Id == hotmailConfig.UserId)?.Email;
|
|
|
+ if (string.IsNullOrEmpty(qwEmail)) continue;
|
|
|
+
|
|
|
+ if (hotmailConfig.UserName.Equals("925554512@qq.com"))
|
|
|
+ {
|
|
|
+ hotmailConfig.UserName = "Roy.Lei.Atom@hotmail.com";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取 AI 为该账号生成的摘要
|
|
|
+ var summary = aiSummaryResults?.FirstOrDefault(x => x.Recipient.Equals(hotmailConfig.UserName, StringComparison.OrdinalIgnoreCase));
|
|
|
+
|
|
|
+ string finalSubject = $"{DateTime.Now:yyyy-MM-dd} - 邮件汇总";
|
|
|
+ string finalBody = "AI 未能成功生成今日摘要。";
|
|
|
+
|
|
|
+ if (summary != null)
|
|
|
+ {
|
|
|
+ finalSubject = $"[AI摘要] {summary.EmailSubject}";
|
|
|
+ finalBody = summary.HtmlBody;
|
|
|
+ }
|
|
|
+
|
|
|
+ await _qiYeWeChatApiService.EmailSendAsync(new EmailRequestDto
|
|
|
+ {
|
|
|
+ ToEmails = new List<string> { qwEmail },
|
|
|
+ Subject = finalSubject,
|
|
|
+ Body = finalBody,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ // 记录解析 JSON 失败日志
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 纯正则实现:剔除 HTML 标签、样式和脚本,保留核心文本
|
|
|
+ /// </summary>
|
|
|
+ private static string CleanHtmlToPlainText(string? html)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrEmpty(html)) return string.Empty;
|
|
|
+
|
|
|
+ // 1. 剔除脚本 (Script) 和 样式 (Style) 及其内部内容
|
|
|
+ html = Regex.Replace(html, @"<(script|style)[^>]*?>.*?</\1>", "", RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
|
|
+
|
|
|
+ // 2. 剔除所有 HTML 标签
|
|
|
+ html = Regex.Replace(html, @"<[^>]*>", " ");
|
|
|
+
|
|
|
+ // 3. 将 HTML 实体字符转换回普通字符 (例如 -> 空格, < -> <)
|
|
|
+ html = HttpUtility.HtmlDecode(html);
|
|
|
+
|
|
|
+ // 4. 清理多余的空白字符和重复换行
|
|
|
+ html = Regex.Replace(html, @"\s+", " "); // 将多个空格/换行合并为一个空格
|
|
|
+ html = Regex.Replace(html, @"(\n\s*){2,}", "\n"); // 压缩重复换行
|
|
|
+
|
|
|
+ return html.Trim();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public static string BuildMailSummaryPrompt(List<MailDto> mailList)
|
|
|
+ {
|
|
|
+ var rawDataJson = System.Text.Json.JsonSerializer.Serialize(mailList, new JsonSerializerOptions { WriteIndented = false });
|
|
|
+
|
|
|
+ return $@"
|
|
|
+# Role: 高级邮件情报官 (Senior Email Intelligence Officer)
|
|
|
+
|
|
|
+## Task
|
|
|
+分析提供的 {mailList.Count} 封原始邮件,排除垃圾内容,并为每个收件人生成 HTML 格式的每日摘要报告。
|
|
|
+
|
|
|
+## Rule & Logic
|
|
|
+1. **Filtering**: 严禁包含:自动订阅、社交媒体动态、验证码、退订链接邮件。
|
|
|
+2. **Analysis**: 对同一收件人的邮件按业务逻辑归类(如:财务类、技术类、会议类)。
|
|
|
+3. **HTML Requirements**:
|
|
|
+ - 必须使用 `border-collapse: collapse; width: 100%;` 的表格。
|
|
|
+ - 主题色使用蓝色 (#2563eb)。
|
|
|
+ - 包含三部分:【核心概览】、【详情表格 (列: 时间, 主题, 来源, 摘要)】、【待办建议 (Action Items)】。
|
|
|
+ - 所有 CSS 必须 Inline Style。
|
|
|
+
|
|
|
+## HTML Format (Strict)
|
|
|
+- 仅允许使用: <h3> (标题), <p> (段落), <ul>/<li> (列表), <strong> (加粗), <hr> (分割线)。
|
|
|
+- 禁止使用: <table>, <div>, <span>, class, id。
|
|
|
+- 样式: 仅在 <h3> 中使用 style=""color:#2563eb""。
|
|
|
+
|
|
|
+## Constraints
|
|
|
+- 输出必须是合法的 JSON 数组,严禁任何前言或后缀文字。
|
|
|
+- 属性名:Recipient, EmailSubject, HtmlBody。
|
|
|
+- HtmlBody 必须是完整的 HTML 字符串,注意 JSON 内部引号转义。
|
|
|
+
|
|
|
+## Input Data (JSON)
|
|
|
+{rawDataJson}
|
|
|
+";
|
|
|
+ }
|
|
|
+
|
|
|
+ private static async Task NotifyEmptyEmails(List<int> userIds)
|
|
|
+ {
|
|
|
+ var userEmails = await _sqlSugar.Queryable<Sys_Users>().Where(x => x.IsDel == 0 && userIds.Contains(x.Id)).Select(x => x.Email).ToListAsync();
|
|
|
+ if (userEmails.Any())
|
|
|
+ {
|
|
|
+ await _qiYeWeChatApiService.EmailSendAsync(new EmailRequestDto
|
|
|
+ {
|
|
|
+ ToEmails = userEmails,
|
|
|
+ Subject = $"{DateTime.Now:yyyy-MM-dd} - 邮件汇总",
|
|
|
+ Body = "昨日暂未收到有效邮件。"
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public class AiSummaryResult
|
|
|
+ {
|
|
|
+ public string Recipient { get; set; } = string.Empty;
|
|
|
+ public string EmailSubject { get; set; } = string.Empty;
|
|
|
+ public string HtmlBody { get; set; } = string.Empty;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|