Res_InvitationAI.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel.DataAnnotations;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Text.Json.Serialization;
  7. using System.Threading.Tasks;
  8. namespace OASystem.Domain.Entities.Resource
  9. {
  10. /// <summary>
  11. /// 商邀公务AI
  12. /// </summary>
  13. [SugarTable("Res_InvitationAI", "商邀公务AI")]
  14. public class Res_InvitationAI: EntityBase
  15. {
  16. /// <summary>
  17. /// 名称
  18. /// </summary>
  19. [SugarColumn(ColumnName = "InvName", ColumnDescription = "名称", IsNullable = true, ColumnDataType = "varchar(150)")]
  20. public string InvName { get; set; }
  21. /// <summary>
  22. /// 团组ID
  23. /// 注:自定义命名时,GroupID = 0;使用团组名称时,GroupID = Grp_DelegationInfo.Id
  24. /// </summary>
  25. [SugarColumn(ColumnName = "GroupId", ColumnDescription = "团组ID", IsNullable = true, ColumnDataType = "int")]
  26. public int GroupId { get; set; }
  27. /// <summary>
  28. /// ai 抓取信息存储(含本地数据信息)
  29. /// </summary>
  30. [SugarColumn(ColumnName = "AiCrawledDetails", ColumnDescription = "ai 抓取信息存储(含本地数据信息)", IsJson = true, IsNullable = true, ColumnDataType = "varchar(max)")]
  31. public List<InvitationAIInfo> AiCrawledDetails { get; set; } = new List<InvitationAIInfo>();
  32. /// <summary>
  33. /// 词条信息
  34. /// </summary>
  35. [SugarColumn(ColumnName = "Entries", ColumnDescription = "词条信息", IsJson = true, IsNullable = true, ColumnDataType = "varchar(max)")]
  36. public EntryInfo EntryInfo { get; set; } = new EntryInfo();
  37. }
  38. /// <summary>
  39. /// 单位信息
  40. /// </summary>
  41. public class InvitationAIInfo
  42. {
  43. /// <summary>
  44. /// Guid
  45. /// </summary>
  46. public string Guid { get; set; }
  47. /// <summary>
  48. /// 复选框是否选中
  49. /// </summary>
  50. public bool IsChecked { get; set; } = false;
  51. /// <summary>
  52. /// 数据来源
  53. /// 0-本地数据;1-第三方AI接口数据;2-用户手动输入数据
  54. /// </summary>
  55. public int Source { get; set; } = 0;
  56. /// <summary>
  57. /// 归属区域
  58. /// </summary>
  59. public string Region { get; set; }
  60. /// <summary>
  61. /// 标准行业:信息技术、金融与财会、工业制造、医疗保健、政府与公共服务、消费与贸易
  62. /// </summary>
  63. public string Industry { get; set; }
  64. /// <summary>
  65. /// 名称(中文)
  66. /// </summary>
  67. public string NameCn { get; set; }
  68. /// <summary>
  69. /// 名称(英文)
  70. /// </summary>
  71. public string NameEn { get; set; }
  72. /// <summary>
  73. /// 地址
  74. /// </summary>
  75. public string Address { get; set; }
  76. /// <summary>
  77. /// 经营范围
  78. /// </summary>
  79. public string Scope { get; set; }
  80. /// <summary>
  81. /// 联系人
  82. /// </summary>
  83. public string Contact { get; set; }
  84. /// <summary>
  85. /// 联系电话
  86. /// </summary>
  87. public string Phone { get; set; }
  88. /// <summary>
  89. /// 联系邮箱
  90. /// </summary>
  91. public string Email { get; set; }
  92. /// <summary>
  93. /// 官网地址
  94. /// </summary>
  95. public string SiteUrl { get; set; }
  96. /// <summary>
  97. /// 文章地址
  98. /// </summary>
  99. public List<PostNewsItem> PostUrl { get; set; } = new List<PostNewsItem>();
  100. /// <summary>
  101. /// 推荐等级
  102. /// </summary>
  103. public string RecLevel { get; set; }
  104. /// <summary>
  105. /// 对接建议
  106. /// </summary>
  107. public string IntgAdvice { get; set; }
  108. /// <summary>
  109. /// 邮件信息
  110. /// </summary>
  111. public EmailInfo EmailInfo { get; set; } = new EmailInfo();
  112. /// <summary>
  113. /// 备注
  114. /// </summary>
  115. public string Remark { get; set; }
  116. /// <summary>
  117. /// 操作时间
  118. /// </summary>
  119. public DateTime OperatedAt { get; set; }
  120. /// <summary>
  121. /// 操作人
  122. /// </summary>
  123. public string Operator { get; set; }
  124. }
  125. /// <summary>
  126. /// 新闻链接信息
  127. /// </summary>
  128. public class PostNewsItem
  129. {
  130. public string Date { get; set; }
  131. public string Description { get; set; }
  132. public string Url { get; set; }
  133. }
  134. public class EntryInfo
  135. {
  136. /// <summary>
  137. /// 出访单位
  138. /// </summary>
  139. public string OriginUnit { get; set; }
  140. /// <summary>
  141. /// 拜访国家
  142. /// </summary>
  143. public List<string> TargetCountry { get; set; } = new List<string>();
  144. /// <summary>
  145. /// 行业信息
  146. /// 信息技术、金融与财会、工业制造、医疗保健、政府与公共服务、消费与贸易
  147. /// </summary>
  148. public List<string> Industries { get; set; } = new List<string>();
  149. /// <summary>
  150. /// 规模类型
  151. /// </summary>
  152. public List<string> ScaleTypes { get; set; } = new List<string>();
  153. /// <summary>
  154. /// 是否需要华人单位背景
  155. /// </summary>
  156. public bool IsBackground { get; set; } = false;
  157. /// <summary>
  158. /// 出访目的
  159. /// </summary>
  160. public string Objective { get; set; }
  161. /// <summary>
  162. /// 数据条数
  163. /// 每个国家获取数据总条数,默认10条
  164. /// </summary>
  165. public int NeedCount { get; set; } = 5;
  166. /// <summary>
  167. /// 其他规则
  168. /// </summary>
  169. public string OtherConstraints { get; set; }
  170. /// <summary>
  171. /// 操作时间
  172. /// </summary>
  173. public DateTime OperatedAt { get; set; } = new DateTime();
  174. /// <summary>
  175. /// 操作人
  176. /// </summary>
  177. public string Operator { get; set; }
  178. }
  179. public class EmailInfo
  180. {
  181. /// <summary>
  182. /// 邮件标题
  183. /// </summary>
  184. public string EmailTitle { get; set; }
  185. /// <summary>
  186. /// 邮箱内容
  187. /// </summary>
  188. public string EmailContent { get; set; }
  189. /// <summary>
  190. /// 附件地址
  191. /// </summary>
  192. public List<string> AttachmentPaths { get; set; }
  193. /// <summary>
  194. /// 发送状态
  195. /// 1.未开始
  196. /// 2.AI生成成功
  197. /// 3.手动编辑
  198. /// 4.发送完成
  199. /// 5.发送失败
  200. /// </summary>
  201. public int Status { get; set; } = 1;
  202. /// <summary>
  203. /// 操作时间
  204. /// </summary>
  205. public DateTime OperatedAt { get; set; }
  206. /// <summary>
  207. /// 操作人
  208. /// </summary>
  209. public string Operator { get; set; }
  210. }
  211. public class AICreateEmailInfo
  212. {
  213. public string Guid { get; set; }
  214. public string NameCn { get; set; }
  215. public string Scope { get; set; }
  216. public string Subject { get; set; }
  217. public string Content { get; set; }
  218. }
  219. public class CountryAIPormptInfo {
  220. public string Country { get; set; }
  221. public int Count { get; set; }
  222. }
  223. #region 行业信息
  224. /// <summary>
  225. /// 行业信息
  226. /// </summary>
  227. public class IndustryNode
  228. {
  229. public string Code { get; init; }
  230. public string NameCn { get; init; }
  231. public string NameEn { get; init; }
  232. public string ParentCode { get; init; }
  233. public List<IndustryNode> Children { get; init; } = new();
  234. public string Keywords { get; init; }
  235. public IndustryNode() { }
  236. /// <summary>
  237. /// 静态缓存:扁平化字典,用于 O(1) 效率查找
  238. /// </summary>
  239. private static readonly Dictionary<string, IndustryNode> _flatCache;
  240. public static List<IndustryNode> Roots { get; }
  241. static IndustryNode()
  242. {
  243. Roots = BuildInitialData();
  244. // 预先扁平化所有节点,方便后续根据 Code 查找
  245. _flatCache = Roots.SelectMany(GetSelfAndChildren).ToDictionary(x => x.Code);
  246. }
  247. /// <summary>
  248. /// 递归获取所有节点(平铺)
  249. /// </summary>
  250. private static IEnumerable<IndustryNode> GetSelfAndChildren(IndustryNode node)
  251. {
  252. yield return node;
  253. if (node.Children == null) yield break;
  254. foreach (var child in node.Children.SelectMany(GetSelfAndChildren))
  255. yield return child;
  256. }
  257. /// <summary>
  258. /// 快速查找节点 (O(1))
  259. /// </summary>
  260. public static IndustryNode FindByCode(string code) =>
  261. !string.IsNullOrEmpty(code) && _flatCache.TryGetValue(code, out var node) ? node : null;
  262. /// <summary>
  263. /// 初始化全球行业分类静态数据
  264. /// </summary>
  265. public static List<IndustryNode> BuildInitialData() => new()
  266. {
  267. new() { Code = "TECH", NameCn = "信息技术", NameEn = "Technology", Keywords = "IT,互联网,软件,AI", Children = new() {
  268. new() { Code = "TECH01", ParentCode = "TECH", NameCn = "软件开发与服务", NameEn = "Software & Services" },
  269. new() { Code = "TECH02", ParentCode = "TECH", NameCn = "硬件与半导体", NameEn = "Hardware & Semiconductors" },
  270. new() { Code = "TECH03", ParentCode = "TECH", NameCn = "人工智能与大数据", NameEn = "AI & Big Data" }
  271. }},
  272. new() { Code = "FIN", NameCn = "金融与财会", NameEn = "Financials", Keywords = "银行,保险,证券", Children = new() {
  273. new() { Code = "FIN01", ParentCode = "FIN", NameCn = "银行业", NameEn = "Banking" },
  274. new() { Code = "FIN02", ParentCode = "FIN", NameCn = "保险与风险管理", NameEn = "Insurance" },
  275. new() { Code = "FIN03", ParentCode = "FIN", NameCn = "资本市场与证券", NameEn = "Capital Markets" }
  276. }},
  277. new() { Code = "MANU", NameCn = "工业制造", NameEn = "Manufacturing", Keywords = "工厂,机械,自动化", Children = new() {
  278. new() { Code = "MANU01", ParentCode = "MANU", NameCn = "汽车与运输设备", NameEn = "Automotive" },
  279. new() { Code = "MANU02", ParentCode = "MANU", NameCn = "机械与电气设备", NameEn = "Machinery & Electrical" },
  280. new() { Code = "MANU03", ParentCode = "MANU", NameCn = "消费电子制造", NameEn = "Consumer Electronics" }
  281. }},
  282. new() { Code = "HLT", NameCn = "医疗保健", NameEn = "Healthcare", Keywords = "制药,医院,器械", Children = new() {
  283. new() { Code = "HLT01", ParentCode = "HLT", NameCn = "制药与生物技术", NameEn = "Pharmaceuticals & Biotech" },
  284. new() { Code = "HLT02", ParentCode = "HLT", NameCn = "医疗器械与供应", NameEn = "Medical Devices" },
  285. new() { Code = "HLT03", ParentCode = "HLT", NameCn = "医疗机构与诊所", NameEn = "Health Institutions" }
  286. }},
  287. new() { Code = "GOV", NameCn = "政府与公共服务", NameEn = "Government", Keywords = "行政,机关,组织,NGO", Children = new() {
  288. new() { Code = "GOV01", ParentCode = "GOV", NameCn = "政府行政机关", NameEn = "Administrative Bodies" },
  289. new() { Code = "GOV02", ParentCode = "GOV", NameCn = "国际组织与NGO", NameEn = "International Orgs & NGOs" },
  290. new() { Code = "GOV03", ParentCode = "GOV", NameCn = "公共教育与科研单位", NameEn = "Education & Research" }
  291. }},
  292. new() { Code = "CONS", NameCn = "消费与贸易", NameEn = "Consumer & Trade", Keywords = "零售,电商,物流", Children = new() {
  293. new() { Code = "CONS01", ParentCode = "CONS", NameCn = "电子商务与零售", NameEn = "E-commerce & Retail" },
  294. new() { Code = "CONS02", ParentCode = "CONS", NameCn = "物流与供应链", NameEn = "Logistics & Supply Chain" },
  295. new() { Code = "CONS03", ParentCode = "CONS", NameCn = "酒店与旅游餐饮", NameEn = "Hospitality & Tourism" }
  296. }}
  297. };
  298. }
  299. #endregion
  300. #region 单位规模信息
  301. /// <summary>
  302. /// 单位规模
  303. /// </summary>
  304. public class OrgScale
  305. {
  306. public string Name { get; init; }
  307. public int MinStaff { get; init; }
  308. public int MaxStaff { get; init; }
  309. public static List<OrgScale> BuildInitialData() => new()
  310. {
  311. new() { Name = "微型 (1-10人)", MinStaff = 1, MaxStaff = 10 },
  312. new() { Name = "小型 (11-50人)", MinStaff = 11, MaxStaff = 50 },
  313. new() { Name = "中型 (51-200人)", MinStaff = 51, MaxStaff = 200 },
  314. new() { Name = "大型 (201-1000人)", MinStaff = 201, MaxStaff = 1000 },
  315. new() { Name = "超大型 (1000人以上)", MinStaff = 1001, MaxStaff = int.MaxValue }
  316. };
  317. /// <summary>
  318. /// 根据人数自动匹配规模标签
  319. /// </summary>
  320. public static string GetLabel(int count) =>
  321. BuildInitialData().FirstOrDefault(s => count >= s.MinStaff && count <= s.MaxStaff)?.Name ?? "未知规模";
  322. }
  323. #endregion
  324. #region AI 行业匹配结果实体
  325. /// <summary>
  326. /// AI 行业匹配结果实体
  327. /// </summary>
  328. public class IndustryMatchResult
  329. {
  330. /// <summary>
  331. /// 原始出访单位名称
  332. /// </summary>
  333. public string SourceUnitName { get; set; } = string.Empty;
  334. /// <summary>
  335. /// 匹配到的目标单位名称(必须与输入 NameCn 一致)
  336. /// </summary>
  337. public string TargetUnitName { get; set; } = string.Empty;
  338. /// <summary>
  339. /// 目标单位所属国家
  340. /// </summary>
  341. public string TargetCountry { get; set; } = string.Empty;
  342. /// <summary>
  343. /// 识别出的行业分类(来自动态传入的行业标准)
  344. /// </summary>
  345. public string MatchedIndustry { get; set; } = string.Empty;
  346. /// <summary>
  347. /// 匹配置信度 (0.0 - 1.0)
  348. /// </summary>
  349. public double ConfidenceScore { get; set; }
  350. /// <summary>
  351. /// AI 给出的匹配理由说明
  352. /// </summary>
  353. public string MatchReason { get; set; } = string.Empty;
  354. // --- 辅助属性 (非 AI 返回内容) ---
  355. /// <summary>
  356. /// 判断是否为高价值匹配(业务逻辑判定)
  357. /// </summary>
  358. [JsonIgnore]
  359. public bool IsHighValue => ConfidenceScore >= 0.8;
  360. }
  361. #endregion
  362. }