|
|
@@ -2,6 +2,7 @@
|
|
|
using Aspose.Words;
|
|
|
using Aspose.Words.Tables;
|
|
|
using EyeSoft.Extensions;
|
|
|
+using NodaTime;
|
|
|
using NPOI.SS.Formula.Functions;
|
|
|
using NPOI.SS.UserModel;
|
|
|
using OASystem.API.OAMethodLib;
|
|
|
@@ -20,6 +21,7 @@ using System.ComponentModel.DataAnnotations;
|
|
|
using System.Data;
|
|
|
using System.Diagnostics;
|
|
|
using TencentCloud.Common;
|
|
|
+using static NodaTime.TimeZones.TzdbZone1970Location;
|
|
|
using static OASystem.API.OAMethodLib.GeneralMethod;
|
|
|
using static OASystem.API.OAMethodLib.JWTHelper;
|
|
|
using static OpenAI.GPT3.ObjectModels.Models;
|
|
|
@@ -2328,11 +2330,23 @@ Inner Join Sys_Department as d With(Nolock) On u.DepId=d.Id Where m.Id={0} ", _m
|
|
|
}));
|
|
|
}
|
|
|
|
|
|
+ var groupInfo = await _sqlSugar.Queryable<Grp_DelegationInfo>().Where(x => x.IsDel == 0 && x.Id == info.GroupId).FirstAsync();
|
|
|
+ // 设置国家、单位默认值
|
|
|
+ if (string.IsNullOrEmpty(info.EntryInfo.OriginUnit))
|
|
|
+ {
|
|
|
+ info.EntryInfo.OriginUnit = groupInfo?.ClientUnit ?? "";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (info.EntryInfo.TargetCountry == null || info.EntryInfo.TargetCountry.Count < 1)
|
|
|
+ {
|
|
|
+ info.EntryInfo.TargetCountry = _delegationInfoRep.GroupSplitCountry(groupInfo?.TeamName ?? "");
|
|
|
+ }
|
|
|
+
|
|
|
var view = new
|
|
|
{
|
|
|
info.Id,
|
|
|
- info.InvName,
|
|
|
info.GroupId,
|
|
|
+ info.InvName,
|
|
|
info.AiCrawledDetails,
|
|
|
Entry = info.EntryInfo,
|
|
|
};
|
|
|
@@ -2368,19 +2382,40 @@ Inner Join Sys_Department as d With(Nolock) On u.DepId=d.Id Where m.Id={0} ", _m
|
|
|
string operatorName = await _sqlSugar.Queryable<Sys_Users>().Where(x => x.IsDel == 0 && x.Id == dto.CurrUserId).Select(x => x.CnName).FirstAsync() ?? "-";
|
|
|
|
|
|
var localInvDatas = new List<InvitationAIInfo>(); // 本地数据源(商邀资料)
|
|
|
-
|
|
|
+ var aiTasks = new List<CountryAIPormptInfo>(); // 记录:国家 -> 需要补齐的数量
|
|
|
#region 本地数据源(商邀资料)
|
|
|
|
|
|
+ var datas = await _sqlSugar.Queryable<Res_InvitationOfficialActivityData>()
|
|
|
+ .Where(x => x.IsDel == 0)
|
|
|
+ .Select(x => new {
|
|
|
+ x.Id,
|
|
|
+ x.Country
|
|
|
+ })
|
|
|
+ .ToListAsync();
|
|
|
+
|
|
|
+ var decryptDatas = new List<Res_InvitationOfficialActivityData>();
|
|
|
+ foreach (var item in datas)
|
|
|
+ {
|
|
|
+ decryptDatas.Add(new() {
|
|
|
+ Id = item.Id,
|
|
|
+ Country = AesEncryptionHelper.Decrypt(item.Country)
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ var localDatas = decryptDatas.Where(x=> !string.IsNullOrEmpty(x.Country) && entryInfo.TargetCountry.Contains(x.Country)).ToList();
|
|
|
+
|
|
|
+ var localDataIds = localDatas.Select(x => x.Id).ToList();
|
|
|
+
|
|
|
var rawData = await _sqlSugar.Queryable<Res_InvitationOfficialActivityData>()
|
|
|
- .Where(x => x.IsDel == 0 && x.Country.Equals(entryInfo.TargetCountry))
|
|
|
+ .Where(x => localDataIds.Contains(x.Id))
|
|
|
.ToListAsync();
|
|
|
|
|
|
- // 解密
|
|
|
- localInvDatas = rawData.AsParallel().AsOrdered().Select(item => new InvitationAIInfo
|
|
|
+ // 解密
|
|
|
+ var localInvDecryptDatas = rawData.AsParallel().AsOrdered().Select(item => new InvitationAIInfo
|
|
|
{
|
|
|
Guid = Guid.NewGuid().ToString("N"),
|
|
|
Source = 0, // 明确来源标识
|
|
|
- Region = entryInfo.OriginUnit,
|
|
|
+ Region = AesEncryptionHelper.Decrypt(item.Country),
|
|
|
NameCn = AesEncryptionHelper.Decrypt(item.UnitName),
|
|
|
Address = AesEncryptionHelper.Decrypt(item.Address),
|
|
|
Scope = AesEncryptionHelper.Decrypt(item.Field),
|
|
|
@@ -2391,15 +2426,26 @@ Inner Join Sys_Department as d With(Nolock) On u.DepId=d.Id Where m.Id={0} ", _m
|
|
|
Operator = operatorName,
|
|
|
}).ToList();
|
|
|
|
|
|
+ // 国家数据条数
|
|
|
+ int targetPerCountry = invAiInfo.EntryInfo?.NeedCount ?? 10;
|
|
|
+ foreach (var countryName in invAiInfo.EntryInfo.TargetCountry)
|
|
|
+ {
|
|
|
+ var countryDatas = localInvDecryptDatas.Where(x => x.Region == countryName).Take(targetPerCountry).ToList();
|
|
|
+ if (countryDatas.Any())
|
|
|
+ {
|
|
|
+ localInvDatas.AddRange(countryDatas);
|
|
|
+ int gap = targetPerCountry - countryDatas.Count;
|
|
|
+ if (gap > 0) aiTasks.Add(new() { Country = countryName, Count = gap });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
#endregion
|
|
|
|
|
|
#region 混元AI 获取商邀资料
|
|
|
|
|
|
var hunyuanAIInvDatas = new List<InvitationAIInfo>();
|
|
|
|
|
|
- int aiNeedCount = Math.Max(0, totalTarget - localInvDatas.Count);
|
|
|
-
|
|
|
- if (aiNeedCount > 0)
|
|
|
+ if (aiTasks != null && aiTasks.Count > 0)
|
|
|
{
|
|
|
question = @$"# [SYSTEM_CONTEXT]
|
|
|
- Role: Senior Business Consultant (Global Supply Chain & Cross-border Trade Expert)
|
|
|
@@ -2407,34 +2453,35 @@ Inner Join Sys_Department as d With(Nolock) On u.DepId=d.Id Where m.Id={0} ", _m
|
|
|
- Target Architecture: .NET 6 DTO Compatible Interface
|
|
|
|
|
|
# [INPUT_CONFIG]
|
|
|
+- Tasks: {{{JsonConvert.SerializeObject(aiTasks)}}}
|
|
|
- OriginUnit: {{{entryInfo.OriginUnit}}}
|
|
|
-- TargetCountry: {{{entryInfo.TargetCountry}}}
|
|
|
- Objective: {{{entryInfo.Objective}}}
|
|
|
-- DataCount: {{{aiNeedCount}}}
|
|
|
- OtherConstraints: {{{entryInfo.OtherConstraints}}}
|
|
|
# [ROLE_DEFINITION]
|
|
|
-你是一位精通全球跨境经贸、海外园区政策及 {{TargetCountry}} 本地准入法规的【顶级商务咨询顾问】。你擅长通过“产业链对等原则(Chain-Parity Principle)”为跨国企业精准匹配具备落地价值的合作伙伴。
|
|
|
+你是一位精通全球跨境经贸、海外园区政策及 Tasks 中的国家本地准入法规的【顶级商务咨询顾问】。你擅长通过“产业链对等原则(Chain-Parity Principle)”为跨国企业精准匹配具备落地价值的合作伙伴。
|
|
|
|
|
|
# [BUSINESS_LOGIC_CoT]
|
|
|
在生成结果前,请严格执行以下思维链拆解:
|
|
|
+1. **ScopePartitioning**: 遍历 Tasks 中的每个国家。
|
|
|
1. **EntityProfiling**: 识别 {{OriginUnit}} 的核心生态位(如:Supply/Demand/Capital/Logistics)。
|
|
|
-2. **ParityMatching**: 检索 {{TargetCountry}} 境内业务闭环对等机构(例如:若 Origin 为分销,则 Target 为源头工厂/种植园)。
|
|
|
+2. **ParityMatching**: 针对每个国家,检索境内业务闭环对等机构。(例如:若 Origin 为分销,则 Target 为源头工厂/种植园)。
|
|
|
3. **RegulatoryCheck**: 验证目标机构的合规性(如:GACC 备案、SPS 协议、或当地政府特许经营权)。
|
|
|
-4. **DataSynthesis**: 针对无法直接获取的动态(如 PostUrl),优先检索其官网 News 频道或 LinkedIn 企业号。
|
|
|
+4. **DataSynthesis**: 必须严格根据每个国家对应的 Count 生成数据条数。针对无法直接获取的动态(如 PostUrl),优先检索其官网 News 频道或 LinkedIn 企业号。
|
|
|
|
|
|
# [CONSTRAINTS_&_STANDARDS]
|
|
|
- **NamingConvention**: 所有 JSON Key 必须严格遵循 **PascalCase**(例如:`UnitNameCn` 而非 `unit_name_cn`)。
|
|
|
- **DataIntegrity**:
|
|
|
- - 必须输出精确的 {{DataCount}} 条记录。
|
|
|
+ - 总条数必须等于 Tasks 中所有 Count 的总和。
|
|
|
- 优先级:Core (核心机构) > Backup (关联替代机构)。
|
|
|
- **ValidationRules**:
|
|
|
- - `Phone`: 必须包含 {{TargetCountry}} 国际区号(如 +856, +66 等)。
|
|
|
+ - `Phone`: 必须包含 Tasks 中的国家国际区号(如 +856, +66 等)。
|
|
|
- `IntgAdvice`: 必须包含“对等性分析”,解释该机构如何与 {{OriginUnit}} 形成业务闭环(50-100字)。
|
|
|
- `Status`: 若字段确实无法获取,统一填充 'N/A',禁止编造。
|
|
|
- **Safety**: 确保推荐机构不涉及敏感黑名单或已破产企业。
|
|
|
|
|
|
# [INFORMATION_SCHEMA]
|
|
|
请将结果填充至以下结构的 JSON 数组中:
|
|
|
+- Region:国家(必须与 Tasks 中的 Country 完全匹配)
|
|
|
- NameCn: 单位名称(中文)
|
|
|
- NameEn: 单位名称(英文)
|
|
|
- Address: 详细地理位置(含省市区街道)
|
|
|
@@ -2515,7 +2562,7 @@ Inner Join Sys_Department as d With(Nolock) On u.DepId=d.Id Where m.Id={0} ", _m
|
|
|
{
|
|
|
x.Guid = Guid.NewGuid().ToString("N");
|
|
|
x.Source = 1;
|
|
|
- x.Region = entryInfo.TargetCountry;
|
|
|
+ //x.Region = entryInfo.TargetCountry;
|
|
|
x.Operator = operatorName;
|
|
|
x.OperatedAt = DateTime.Now;
|
|
|
return x;
|
|
|
@@ -2568,7 +2615,7 @@ Inner Join Sys_Department as d With(Nolock) On u.DepId=d.Id Where m.Id={0} ", _m
|
|
|
public async Task<IActionResult> InvitationAISetPrompt(InvitationAISetPromptDto dto)
|
|
|
{
|
|
|
// 基础校验
|
|
|
- if (string.IsNullOrWhiteSpace(dto.OriginUnit) || string.IsNullOrWhiteSpace(dto.TargetCountry))
|
|
|
+ if (string.IsNullOrWhiteSpace(dto.OriginUnit) || dto.TargetCountry == null || dto.TargetCountry.Count == 0)
|
|
|
return Ok(JsonView(false, "请传入有效的单位名称和国家!"));
|
|
|
|
|
|
var groupInfo = await _sqlSugar.Queryable<Grp_DelegationInfo>()
|
|
|
@@ -2576,7 +2623,7 @@ Inner Join Sys_Department as d With(Nolock) On u.DepId=d.Id Where m.Id={0} ", _m
|
|
|
.Select(x => new { x.TeamName, x.VisitPurpose })
|
|
|
.FirstAsync();
|
|
|
|
|
|
- string invName = $"{dto.OriginUnit}拜访{dto.TargetCountry}";
|
|
|
+ string invName = $"{dto.OriginUnit}拜访{string.Join("、",dto.TargetCountry)}";
|
|
|
|
|
|
#region 数据库操作
|
|
|
|
|
|
@@ -2739,15 +2786,28 @@ Inner Join Sys_Department as d With(Nolock) On u.DepId=d.Id Where m.Id={0} ", _m
|
|
|
|
|
|
var entryInfo = invAiInfo.EntryInfo;
|
|
|
|
|
|
+ // 记录:国家 -> 需要补齐的数量
|
|
|
+ var aiTasks = new List<CountryAIPormptInfo>();
|
|
|
+
|
|
|
+ // 单个国家数据总条数
|
|
|
+ int targetPerCountry = invAiInfo.EntryInfo?.NeedCount ?? 10;
|
|
|
+
|
|
|
+ foreach (var countryName in entryInfo.TargetCountry)
|
|
|
+ {
|
|
|
+ var countryDataCount = invAiInfo.AiCrawledDetails.Count(x => x.Region == countryName);
|
|
|
+ int aiNeedCount = targetPerCountry - countryDataCount;
|
|
|
+ if (aiNeedCount > 0)
|
|
|
+ {
|
|
|
+ aiTasks.Add(new() { Country = countryName, Count = aiNeedCount });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 已搜索出的数据(AI 数据源)
|
|
|
var hunyuanAIDatas = invAiInfo.AiCrawledDetails.Where(x => x.Source == 1).ToList() ?? new List<InvitationAIInfo>();
|
|
|
|
|
|
// 当前企业领域
|
|
|
string industryFocus = string.Empty;
|
|
|
|
|
|
- // 动态计算 AI 需求缺口
|
|
|
- int totalTarget = entryInfo.NeedCount;
|
|
|
-
|
|
|
// 词条
|
|
|
string question = string.Empty;
|
|
|
|
|
|
@@ -2757,13 +2817,11 @@ Inner Join Sys_Department as d With(Nolock) On u.DepId=d.Id Where m.Id={0} ", _m
|
|
|
|
|
|
var hunyuanAIInvDatas = new List<InvitationAIInfo>();
|
|
|
|
|
|
- int aiNeedCount = Math.Max(0, totalTarget - hunyuanAIDatas.Count);
|
|
|
-
|
|
|
// 已存在数据名称整理
|
|
|
var existingNames = new HashSet<string>(hunyuanAIDatas.Select(x => x.NameCn));
|
|
|
entryInfo.OtherConstraints = $"请基于以下已存在的名称列表进行推荐,避免重复:{string.Join(", ", existingNames)}。{entryInfo.OtherConstraints}";
|
|
|
|
|
|
- if (aiNeedCount > 0)
|
|
|
+ if (aiTasks != null && aiTasks.Count > 0)
|
|
|
{
|
|
|
question = @$"# [SYSTEM_CONTEXT]
|
|
|
- Role: Senior Business Consultant (Global Supply Chain & Cross-border Trade Expert)
|
|
|
@@ -2771,34 +2829,35 @@ Inner Join Sys_Department as d With(Nolock) On u.DepId=d.Id Where m.Id={0} ", _m
|
|
|
- Target Architecture: .NET 6 DTO Compatible Interface
|
|
|
|
|
|
# [INPUT_CONFIG]
|
|
|
+- Tasks: {{{JsonConvert.SerializeObject(aiTasks)}}}
|
|
|
- OriginUnit: {{{entryInfo.OriginUnit}}}
|
|
|
-- TargetCountry: {{{entryInfo.TargetCountry}}}
|
|
|
- Objective: {{{entryInfo.Objective}}}
|
|
|
-- DataCount: {{{aiNeedCount}}}
|
|
|
- OtherConstraints: {{{entryInfo.OtherConstraints}}}
|
|
|
# [ROLE_DEFINITION]
|
|
|
-你是一位精通全球跨境经贸、海外园区政策及 {{TargetCountry}} 本地准入法规的【顶级商务咨询顾问】。你擅长通过“产业链对等原则(Chain-Parity Principle)”为跨国企业精准匹配具备落地价值的合作伙伴。
|
|
|
+你是一位精通全球跨境经贸、海外园区政策及 Tasks 中的国家本地准入法规的【顶级商务咨询顾问】。你擅长通过“产业链对等原则(Chain-Parity Principle)”为跨国企业精准匹配具备落地价值的合作伙伴。
|
|
|
|
|
|
# [BUSINESS_LOGIC_CoT]
|
|
|
在生成结果前,请严格执行以下思维链拆解:
|
|
|
+1. **ScopePartitioning**: 遍历 Tasks 中的每个国家。
|
|
|
1. **EntityProfiling**: 识别 {{OriginUnit}} 的核心生态位(如:Supply/Demand/Capital/Logistics)。
|
|
|
-2. **ParityMatching**: 检索 {{TargetCountry}} 境内业务闭环对等机构(例如:若 Origin 为分销,则 Target 为源头工厂/种植园)。
|
|
|
+2. **ParityMatching**: 针对每个国家,检索境内业务闭环对等机构。(例如:若 Origin 为分销,则 Target 为源头工厂/种植园)。
|
|
|
3. **RegulatoryCheck**: 验证目标机构的合规性(如:GACC 备案、SPS 协议、或当地政府特许经营权)。
|
|
|
-4. **DataSynthesis**: 针对无法直接获取的动态(如 PostUrl),优先检索其官网 News 频道或 LinkedIn 企业号。
|
|
|
+4. **DataSynthesis**: 必须严格根据每个国家对应的 Count 生成数据条数。针对无法直接获取的动态(如 PostUrl),优先检索其官网 News 频道或 LinkedIn 企业号。
|
|
|
|
|
|
# [CONSTRAINTS_&_STANDARDS]
|
|
|
- **NamingConvention**: 所有 JSON Key 必须严格遵循 **PascalCase**(例如:`UnitNameCn` 而非 `unit_name_cn`)。
|
|
|
- **DataIntegrity**:
|
|
|
- - 必须输出精确的 {{DataCount}} 条记录。
|
|
|
+ - 总条数必须等于 Tasks 中所有 Count 的总和。
|
|
|
- 优先级:Core (核心机构) > Backup (关联替代机构)。
|
|
|
- **ValidationRules**:
|
|
|
- - `Phone`: 必须包含 {{TargetCountry}} 国际区号(如 +856, +66 等)。
|
|
|
+ - `Phone`: 必须包含 Tasks 中的国家国际区号(如 +856, +66 等)。
|
|
|
- `IntgAdvice`: 必须包含“对等性分析”,解释该机构如何与 {{OriginUnit}} 形成业务闭环(50-100字)。
|
|
|
- `Status`: 若字段确实无法获取,统一填充 'N/A',禁止编造。
|
|
|
- **Safety**: 确保推荐机构不涉及敏感黑名单或已破产企业。
|
|
|
|
|
|
# [INFORMATION_SCHEMA]
|
|
|
请将结果填充至以下结构的 JSON 数组中:
|
|
|
+- Region:国家(必须与 Tasks 中的 Country 完全匹配)
|
|
|
- NameCn: 单位名称(中文)
|
|
|
- NameEn: 单位名称(英文)
|
|
|
- Address: 详细地理位置(含省市区街道)
|
|
|
@@ -2879,7 +2938,7 @@ Inner Join Sys_Department as d With(Nolock) On u.DepId=d.Id Where m.Id={0} ", _m
|
|
|
{
|
|
|
x.Guid = Guid.NewGuid().ToString("N");
|
|
|
x.Source = 1;
|
|
|
- x.Region = entryInfo.TargetCountry;
|
|
|
+ //x.Region = entryInfo.TargetCountry;
|
|
|
x.Operator = operatorName;
|
|
|
x.OperatedAt = DateTime.Now;
|
|
|
return x;
|
|
|
@@ -3456,8 +3515,8 @@ Inner Join Sys_Department as d With(Nolock) On u.DepId=d.Id Where m.Id={0} ", _m
|
|
|
var req = new EmailRequestDto()
|
|
|
{
|
|
|
ToEmails = new List<string> { item.Email },
|
|
|
- CcEmails = new List<string> { userInfo.Email },
|
|
|
- BccEmails = new List<string> { userInfo.Email },
|
|
|
+ //CcEmails = new List<string> { userInfo.Email },
|
|
|
+ //BccEmails = new List<string> { userInfo.Email },
|
|
|
Subject = item.EmailInfo.EmailTitle,
|
|
|
Body = item.EmailInfo.EmailContent,
|
|
|
Files = Array.Empty<IFormFile>()
|