feat: extract global AI service and persist sales-product publish AI reports

Move provider/chat APIs from /xhs/ai to /ai, rename t_ai_provider, and require adopted AI analysis on price publish.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zzh 2026-08-01 15:55:30 +08:00
parent d30375ba49
commit 592054f062
24 changed files with 233 additions and 145 deletions

9
db.sql
View File

@ -29,6 +29,7 @@ DROP TABLE IF EXISTS `role_data_scope`;
DROP TABLE IF EXISTS `role_org_perm`;
DROP TABLE IF EXISTS `user_org_perm`;
DROP TABLE IF EXISTS `t_xhs_media`;
DROP TABLE IF EXISTS `t_ai_provider`;
DROP TABLE IF EXISTS `t_xhs_ai_provider`;
DROP TABLE IF EXISTS `t_xhs_human_config`;
DROP TABLE IF EXISTS `t_xhs_skill`;
@ -1733,7 +1734,7 @@ CREATE TABLE `t_xhs_human_config` (
UNIQUE KEY `uk_xhs_human_customer` (`CustomerId`)
) COMMENT='小红书拟人行为与防封配置表';
CREATE TABLE `t_xhs_ai_provider` (
CREATE TABLE `t_ai_provider` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID;0 表示全局',
`ProviderKey` VARCHAR(32) NOT NULL COMMENT 'ai_chatgpt / ai_zhipu 等',
@ -1751,9 +1752,9 @@ CREATE TABLE `t_xhs_ai_provider` (
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_xhs_ai_provider` (`CustomerId`, `ProviderKey`),
KEY `idx_xhs_ai_customer` (`CustomerId`, `Enabled`)
) COMMENT='小红书 AI 提供商配置表';
UNIQUE KEY `uk_ai_provider` (`CustomerId`, `ProviderKey`),
KEY `idx_ai_customer` (`CustomerId`, `Enabled`)
) COMMENT='全局 AI 提供商配置表(CustomerId=0 表示平台级)';
CREATE TABLE `t_xhs_media` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',

View File

@ -0,0 +1,16 @@
-- 全局 AI 提供商:从小红书域表迁出(未上线环境可直接改名)
-- 若表尚不存在则跳过;若已是 t_ai_provider 则无需执行。
RENAME TABLE `t_xhs_ai_provider` TO `t_ai_provider`;
ALTER TABLE `t_ai_provider`
COMMENT = '全局 AI 提供商配置表(CustomerId=0 表示平台级)';
-- 索引名顺带规范化(可选,失败可忽略)
ALTER TABLE `t_ai_provider`
DROP INDEX `uk_xhs_ai_provider`,
ADD UNIQUE KEY `uk_ai_provider` (`CustomerId`, `ProviderKey`);
ALTER TABLE `t_ai_provider`
DROP INDEX `idx_xhs_ai_customer`,
ADD KEY `idx_ai_customer` (`CustomerId`, `Enabled`);

View File

@ -0,0 +1,3 @@
-- 销售产品价格发布记录:保存 AI 风险分析报告
ALTER TABLE `t_sales_product_publish_record`
ADD COLUMN `AiAnalysisReport` MEDIUMTEXT NULL COMMENT '价格发布AI风险分析报告' AFTER `Description`;

View File

@ -0,0 +1,72 @@
using System.ComponentModel.DataAnnotations;
namespace Oms.Application.Dtos.Ai;
public class AiProviderOutput
{
public int Id { get; set; }
public string ProviderKey { get; set; } = string.Empty;
public string ProviderType { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public string BaseUrl { get; set; } = string.Empty;
public string? ApiKey { get; set; }
public string? ApiSecret { get; set; }
public bool IsDefault { get; set; }
public bool Enabled { get; set; }
}
public class AiProviderSaveInput
{
[Required]
public string ProviderKey { get; set; } = string.Empty;
[Required]
public string ProviderType { get; set; } = string.Empty;
[Required]
public string DisplayName { get; set; } = string.Empty;
[Required]
public string BaseUrl { get; set; } = string.Empty;
public string? ApiKey { get; set; }
public string? ApiSecret { get; set; }
public bool IsDefault { get; set; }
public bool Enabled { get; set; } = true;
}
public class AiChatInput
{
[Required]
public string ProviderKey { get; set; } = string.Empty;
public string? Model { get; set; }
[Required]
public List<AiChatMessageInput> Messages { get; set; } = [];
public string Scene { get; set; } = "assistant";
}
public class AiChatMessageInput
{
public string Role { get; set; } = "user";
public string Content { get; set; } = string.Empty;
}
public class AiChatOutput
{
public string Content { get; set; } = string.Empty;
}

View File

@ -15,6 +15,11 @@ public class SalesProductPriceSaveAllInput
/// </summary>
public bool Publish { get; set; }
/// <summary>
/// 价格发布 AI 风险分析报告(Publish=true 时必填)。
/// </summary>
public string? AiAnalysisReport { get; set; }
/// <summary>
/// 价格项集合。
/// </summary>

View File

@ -19,4 +19,9 @@ public class SalesProductPublishInput
/// 描述。
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 价格发布 AI 风险分析报告(operatorType=price 时必填)。
/// </summary>
public string? AiAnalysisReport { get; set; }
}

View File

@ -45,6 +45,11 @@ public class SalesProductPublishRecordOutput
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 价格发布 AI 风险分析报告。
/// </summary>
public string? AiAnalysisReport { get; set; }
/// <summary>
/// 内容。
/// </summary>

View File

@ -320,75 +320,6 @@ public class XhsSkillSaveInput
public object? Recipe { get; set; }
}
public class XhsAiProviderOutput
{
public int Id { get; set; }
public string ProviderKey { get; set; } = string.Empty;
public string ProviderType { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public string BaseUrl { get; set; } = string.Empty;
public string? ApiKey { get; set; }
public string? ApiSecret { get; set; }
public bool IsDefault { get; set; }
public bool Enabled { get; set; }
}
public class XhsAiProviderSaveInput
{
[Required]
public string ProviderKey { get; set; } = string.Empty;
[Required]
public string ProviderType { get; set; } = string.Empty;
[Required]
public string DisplayName { get; set; } = string.Empty;
[Required]
public string BaseUrl { get; set; } = string.Empty;
public string? ApiKey { get; set; }
public string? ApiSecret { get; set; }
public bool IsDefault { get; set; }
public bool Enabled { get; set; } = true;
}
public class XhsAiChatInput
{
[Required]
public string ProviderKey { get; set; } = string.Empty;
public string? Model { get; set; }
[Required]
public List<XhsAiChatMessageInput> Messages { get; set; } = [];
public string Scene { get; set; } = "assistant";
}
public class XhsAiChatMessageInput
{
public string Role { get; set; } = "user";
public string Content { get; set; } = string.Empty;
}
public class XhsAiChatOutput
{
public string Content { get; set; } = string.Empty;
}
public class XhsAnalysisStartInput
{
[Required]

View File

@ -55,7 +55,7 @@ public class OmsApplicationModule : FakeModule
context.Services.AddOmsItfxIntegration(configuration);
context.Services.AddOmsPlatformShopIntegration(configuration);
context.Services.AddOmsOrderBatchMessaging(configuration);
context.Services.AddXhsLlmClient();
context.Services.AddAiLlmClient();
context.Services.AddHostedService<XhsScheduledPublishWorker>();
context.Services.AddHostedService<MarketingBackgroundWorker>();
}

View File

@ -1,48 +1,51 @@
using Fake.Application;
using Microsoft.AspNetCore.Mvc;
using Oms.Application.Dtos.Ai;
using Oms.Application.Dtos.Shared;
using Oms.Application.Dtos.Xhs;
using Oms.Application.Shared;
using Oms.Domain.AiAggregate.Entities;
using Oms.Domain.AiAggregate.Repositories;
using Oms.Domain.CustomersAggregate.Repositories;
using Oms.Domain.XhsAggregate.Entities;
using Oms.Domain.XhsAggregate.Repositories;
namespace Oms.Application.Services.Xhs;
namespace Oms.Application.Services.Ai;
[ApiExplorerSettings(GroupName = "OMS-Xhs")]
public class XhsAiService : ApplicationService
/// <summary>
/// 全局 AI 提供商与对话服务(系统级,非业务域专属)。
/// </summary>
[ApiExplorerSettings(GroupName = "OMS-Ai")]
public class AiService : ApplicationService
{
private const string SecretMask = "******";
private IXhsAiProviderRepository AiProviderRepository => LazyServiceProvider.GetRequiredService<IXhsAiProviderRepository>();
private IAiProviderRepository AiProviderRepository => LazyServiceProvider.GetRequiredService<IAiProviderRepository>();
private ICustomerRepository CustomerRepository => LazyServiceProvider.GetRequiredService<ICustomerRepository>();
/// <summary>
/// 查询AI服务商列表
/// 查询 AI 服务商列表。
/// </summary>
[HttpPost("/xhs/ai/provider/list")]
public async Task<OmsItemsResult<XhsAiProviderOutput>> ListProvidersAsync()
[HttpPost("/ai/provider/list")]
public async Task<OmsItemsResult<AiProviderOutput>> ListProvidersAsync()
{
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var items = await AiProviderRepository.GetListAsync(x => x.CustomerId == customerId || x.CustomerId == 0);
return new OmsItemsResult<XhsAiProviderOutput>
return new OmsItemsResult<AiProviderOutput>
{
Items = items.Select(x => MapProvider(x, maskSecret: true)).ToList()
};
}
/// <summary>
/// 保存AI服务商配置
/// 保存 AI 服务商配置。
/// </summary>
[HttpPost("/xhs/ai/provider/save")]
public async Task<XhsAiProviderOutput> SaveProviderAsync(XhsAiProviderSaveInput input)
[HttpPost("/ai/provider/save")]
public async Task<AiProviderOutput> SaveProviderAsync(AiProviderSaveInput input)
{
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var providerKey = input.ProviderKey.Trim();
var entity = await AiProviderRepository.GetByProviderKeyAsync(customerId, providerKey);
if (entity == null)
{
entity = new XhsAiProvider { CustomerId = customerId, ProviderKey = providerKey };
entity = new AiProvider { CustomerId = customerId, ProviderKey = providerKey };
}
entity.ProviderType = input.ProviderType.Trim();
@ -85,22 +88,22 @@ public class XhsAiService : ApplicationService
}
/// <summary>
/// AI对话
/// AI 对话。
/// </summary>
[HttpPost("/xhs/ai/chat")]
public async Task<XhsAiChatOutput> ChatAsync(XhsAiChatInput input)
[HttpPost("/ai/chat")]
public async Task<AiChatOutput> ChatAsync(AiChatInput input)
{
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var provider = await ResolveProviderAsync(customerId, input.ProviderKey.Trim());
var llm = LazyServiceProvider.GetRequiredService<XhsLlmClient>();
var llm = LazyServiceProvider.GetRequiredService<AiLlmClient>();
var content = await llm.ChatCompletionAsync(
provider,
input.Messages.Select(x => (x.Role, x.Content)).ToList(),
input.Model);
return new XhsAiChatOutput { Content = content };
return new AiChatOutput { Content = content };
}
internal async Task<XhsAiProvider> ResolveProviderAsync(int customerId, string providerKey)
internal async Task<AiProvider> ResolveProviderAsync(int customerId, string providerKey)
{
var provider = await AiProviderRepository.GetByProviderKeyAsync(customerId, providerKey);
if (provider == null || !provider.Enabled)
@ -116,7 +119,7 @@ public class XhsAiService : ApplicationService
return provider;
}
private static XhsAiProviderOutput MapProvider(XhsAiProvider entity, bool maskSecret) => new()
private static AiProviderOutput MapProvider(AiProvider entity, bool maskSecret) => new()
{
Id = entity.Id,
ProviderKey = entity.ProviderKey,

View File

@ -153,6 +153,7 @@ public partial class SalesProductService
PublishUser = entity.PublishUser,
PublishTime = entity.PublishTime,
Description = entity.Description,
AiAnalysisReport = entity.AiAnalysisReport,
Content = operatorType == PriceOperatorType
? OmsDocHelper.ParseSalesProductPricePublishContentForApi(entity.Content)
: OmsDocHelper.ToSnapshotApiContent(OmsDocHelper.DeserializeRulesSnapshot(entity.Content)),
@ -227,7 +228,11 @@ public partial class SalesProductService
/// <summary>
/// 为当前配置生成发布快照。
/// </summary>
private async Task CreatePublishRecordAsync(int salesProductId, string operatorType, string? description)
private async Task CreatePublishRecordAsync(
int salesProductId,
string operatorType,
string? description,
string? aiAnalysisReport = null)
{
object snapshot = operatorType == PriceOperatorType
? await BuildPricePublishSnapshotAsync(salesProductId)
@ -243,6 +248,7 @@ public partial class SalesProductService
PublishUser = string.IsNullOrWhiteSpace(CurrentUser.UserName) ? CurrentUser.GetId<int>().ToString() : CurrentUser.UserName!,
PublishTime = DateTime.Now,
Description = description,
AiAnalysisReport = string.IsNullOrWhiteSpace(aiAnalysisReport) ? null : aiAnalysisReport.Trim(),
Content = OmsDocHelper.SerializeSnapshotJson(snapshot)
});
}

View File

@ -262,7 +262,16 @@ public partial class SalesProductService : ApplicationService
await SalesProductRepository.ReplacePricesAsync(input.SalesProductId, prices, factors, details);
if (input.Publish)
{
await CreatePublishRecordAsync(input.SalesProductId, PriceOperatorType, "保存并发布价格");
if (string.IsNullOrWhiteSpace(input.AiAnalysisReport))
{
throw new Fake.Application.BusinessException("价格发布前须完成 AI 风险分析并保存报告");
}
await CreatePublishRecordAsync(
input.SalesProductId,
PriceOperatorType,
"保存并发布价格",
input.AiAnalysisReport);
}
}
@ -349,7 +358,17 @@ public partial class SalesProductService : ApplicationService
[HttpPost("/channel/sales-product/publish")]
public async Task PublishAsync(SalesProductPublishInput input)
{
await CreatePublishRecordAsync(input.SalesProductId, NormalizeOperatorType(input.OperatorType), input.Description);
var operatorType = NormalizeOperatorType(input.OperatorType);
if (operatorType == PriceOperatorType && string.IsNullOrWhiteSpace(input.AiAnalysisReport))
{
throw new Fake.Application.BusinessException("价格发布前须完成 AI 风险分析并保存报告");
}
await CreatePublishRecordAsync(
input.SalesProductId,
operatorType,
input.Description,
input.AiAnalysisReport);
}
/// <summary>

View File

@ -7,10 +7,10 @@ using Oms.Application.Dtos.Mcp;
using Oms.Application.Dtos.Shared;
using Oms.Application.Mcp;
using Oms.Application.Shared;
using Oms.Domain.AiAggregate.Repositories;
using Oms.Domain.CustomersAggregate.Repositories;
using Oms.Domain.McpAggregate.Entities;
using Oms.Domain.McpAggregate.Repositories;
using Oms.Domain.XhsAggregate.Repositories;
namespace Oms.Application.Services.Mcp;
@ -19,9 +19,9 @@ public class McpToolService : ApplicationService
{
private IMcpToolRepository McpToolRepository => LazyServiceProvider.GetRequiredService<IMcpToolRepository>();
private IMcpToolExecutor ToolExecutor => LazyServiceProvider.GetRequiredService<IMcpToolExecutor>();
private IXhsAiProviderRepository AiProviderRepository => LazyServiceProvider.GetRequiredService<IXhsAiProviderRepository>();
private IAiProviderRepository AiProviderRepository => LazyServiceProvider.GetRequiredService<IAiProviderRepository>();
private ICustomerRepository CustomerRepository => LazyServiceProvider.GetRequiredService<ICustomerRepository>();
private XhsLlmClient LlmClient => LazyServiceProvider.GetRequiredService<XhsLlmClient>();
private AiLlmClient LlmClient => LazyServiceProvider.GetRequiredService<AiLlmClient>();
/// <summary>列出 MCP 工具(内置目录 + 库表覆盖)</summary>
[HttpPost("/mcp/tool/list")]
@ -307,7 +307,7 @@ public class McpToolService : ApplicationService
return enabled;
}
private async Task<Oms.Domain.XhsAggregate.Entities.XhsAiProvider> ResolveProviderAsync(
private async Task<Oms.Domain.AiAggregate.Entities.AiProvider> ResolveProviderAsync(
int customerId,
string providerKey)
{

View File

@ -4,8 +4,8 @@ using Fake.Application;
using Microsoft.AspNetCore.Mvc;
using Oms.Application.Dtos.Orders;
using Oms.Application.Shared;
using Oms.Domain.XhsAggregate.Entities;
using Oms.Domain.XhsAggregate.Repositories;
using Oms.Domain.AiAggregate.Entities;
using Oms.Domain.AiAggregate.Repositories;
namespace Oms.Application.Services.Orders;
@ -20,10 +20,10 @@ public partial class OrderService
"地址1",
];
private IXhsAiProviderRepository AiProviderRepository =>
LazyServiceProvider.GetRequiredService<IXhsAiProviderRepository>();
private IAiProviderRepository AiProviderRepository =>
LazyServiceProvider.GetRequiredService<IAiProviderRepository>();
private XhsLlmClient LlmClient => LazyServiceProvider.GetRequiredService<XhsLlmClient>();
private AiLlmClient LlmClient => LazyServiceProvider.GetRequiredService<AiLlmClient>();
/// <summary>
/// AI 解析粘贴的收件地址文本,并校验是否完整。
@ -122,7 +122,7 @@ public partial class OrderService
};
}
private async Task<XhsAiProvider> ResolveAiProviderAsync(int customerId, string? providerKey)
private async Task<AiProvider> ResolveAiProviderAsync(int customerId, string? providerKey)
{
var key = (providerKey ?? string.Empty).Trim();
if (!string.IsNullOrWhiteSpace(key))

View File

@ -2,6 +2,7 @@ using Fake.Application;
using Microsoft.AspNetCore.Mvc;
using Oms.Application.Dtos.Shared;
using Oms.Application.Dtos.Xhs;
using Oms.Application.Services.Ai;
using Oms.Application.Shared;
using Oms.Domain.CustomersAggregate.Repositories;
using Oms.Domain.XhsAggregate.Consts;
@ -110,9 +111,9 @@ public class XhsAnalysisService : ApplicationService
throw new BusinessException("请先完成笔记采集");
}
var aiService = LazyServiceProvider.GetRequiredService<XhsAiService>();
var aiService = LazyServiceProvider.GetRequiredService<AiService>();
var provider = await aiService.ResolveProviderAsync(customerId, input.ProviderKey.Trim());
var llm = LazyServiceProvider.GetRequiredService<XhsLlmClient>();
var llm = LazyServiceProvider.GetRequiredService<AiLlmClient>();
var skillHint = string.Empty;
if (input.SkillId is > 0)

View File

@ -1,6 +1,7 @@
using Fake.Application;
using Microsoft.AspNetCore.Mvc;
using Oms.Application.Dtos.Xhs;
using Oms.Application.Services.Ai;
using Oms.Application.Shared;
using Oms.Domain.CustomersAggregate.Repositories;
using Oms.Domain.XhsAggregate.Consts;
@ -66,9 +67,9 @@ public class XhsCreationService : ApplicationService
public async Task<XhsCreationGenerateOutput> GenerateAsync(XhsCreationGenerateInput input)
{
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var aiService = LazyServiceProvider.GetRequiredService<XhsAiService>();
var aiService = LazyServiceProvider.GetRequiredService<AiService>();
var provider = await aiService.ResolveProviderAsync(customerId, input.ProviderKey.Trim());
var llm = LazyServiceProvider.GetRequiredService<XhsLlmClient>();
var llm = LazyServiceProvider.GetRequiredService<AiLlmClient>();
var skillHint = string.Empty;
if (input.SkillId is > 0)

View File

@ -1,11 +1,11 @@
using System.Net.Http.Headers;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using Fake.Application;
using Microsoft.Extensions.DependencyInjection;
using Oms.Application.Mcp;
using Oms.Domain.XhsAggregate.Entities;
using Oms.Domain.AiAggregate.Entities;
namespace Oms.Application.Shared;
@ -40,21 +40,21 @@ public class LlmChatResult
}
/// <summary>
/// OpenAI 兼容 Chat Completions 客户端(智谱 / DeepSeek / 豆包等)。
/// OpenAI 兼容 Chat Completions 客户端(通义 / DeepSeek / 豆包等)。
/// </summary>
public class XhsLlmClient
public class AiLlmClient
{
public const string HttpClientName = nameof(XhsLlmClient);
public const string HttpClientName = nameof(AiLlmClient);
private readonly IHttpClientFactory _httpClientFactory;
public XhsLlmClient(IHttpClientFactory httpClientFactory)
public AiLlmClient(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task<string> ChatCompletionAsync(
XhsAiProvider provider,
AiProvider provider,
IReadOnlyList<(string Role, string Content)> messages,
string? modelOverride = null,
CancellationToken cancellationToken = default)
@ -69,7 +69,7 @@ public class XhsLlmClient
}
public async Task<LlmChatResult> ChatCompletionDetailedAsync(
XhsAiProvider provider,
AiProvider provider,
IReadOnlyList<LlmChatMessage> messages,
IReadOnlyList<LlmToolDefinition>? tools = null,
string? modelOverride = null,
@ -258,11 +258,11 @@ public class XhsLlmClient
}
}
public static class XhsLlmServiceExtensions
public static class AiLlmServiceExtensions
{
public static IServiceCollection AddXhsLlmClient(this IServiceCollection services)
public static IServiceCollection AddAiLlmClient(this IServiceCollection services)
{
services.AddHttpClient(XhsLlmClient.HttpClientName, client =>
services.AddHttpClient(AiLlmClient.HttpClientName, client =>
{
client.Timeout = TimeSpan.FromMinutes(3);
});
@ -270,7 +270,8 @@ public static class XhsLlmServiceExtensions
{
client.Timeout = TimeSpan.FromSeconds(45);
});
services.AddTransient<XhsLlmClient>();
services.AddTransient<AiLlmClient>();
return services;
}
}

View File

@ -1,10 +1,13 @@
using Oms.Domain.Shared;
using SqlSugar;
namespace Oms.Domain.XhsAggregate.Entities;
namespace Oms.Domain.AiAggregate.Entities;
[SugarTable("t_xhs_ai_provider")]
public class XhsAiProvider : OmsAuditedAggregateRoot
/// <summary>
/// 全局 AI 提供商配置(CustomerId=0 表示平台级)。
/// </summary>
[SugarTable("t_ai_provider")]
public class AiProvider : OmsAuditedAggregateRoot
{
public int CustomerId { get; set; }

View File

@ -0,0 +1,9 @@
using Fake.Domain.Repositories;
using Oms.Domain.AiAggregate.Entities;
namespace Oms.Domain.AiAggregate.Repositories;
public interface IAiProviderRepository : IRepository<AiProvider>
{
Task<AiProvider?> GetByProviderKeyAsync(int customerId, string providerKey, CancellationToken cancellationToken = default);
}

View File

@ -21,6 +21,12 @@ public class SalesProductPublishRecord : OmsAuditedEntity
public string? Description { get; set; }
/// <summary>
/// 价格发布 AI 风险分析报告(operatorType=price 时必填)。
/// </summary>
[SugarColumn(ColumnDataType = "mediumtext", IsNullable = true)]
public string? AiAnalysisReport { get; set; }
[SugarColumn(ColumnDataType = "json", IsNullable = true)]
public string? Content { get; set; }
}

View File

@ -51,9 +51,4 @@ public interface IXhsHumanConfigRepository : IRepository<XhsHumanConfig>
Task<XhsHumanConfig?> GetByCustomerIdAsync(int customerId, CancellationToken cancellationToken = default);
}
public interface IXhsAiProviderRepository : IRepository<XhsAiProvider>
{
Task<XhsAiProvider?> GetByProviderKeyAsync(int customerId, string providerKey, CancellationToken cancellationToken = default);
}
public interface IXhsMediaRepository : IRepository<XhsMedia>;

View File

@ -0,0 +1,16 @@
using Fake.DependencyInjection;
using Oms.Domain.AiAggregate.Entities;
using Oms.Domain.AiAggregate.Repositories;
using Oms.SqlSugarCore.Repositories;
namespace Oms.SqlSugarCore.Ai;
public class AiProviderRepository
: OmsSqlSugarRepository<AiProvider>, IAiProviderRepository, IScopedDependency
{
public Task<AiProvider?> GetByProviderKeyAsync(
int customerId,
string providerKey,
CancellationToken cancellationToken = default) =>
FirstOrDefaultAsync(x => x.CustomerId == customerId && x.ProviderKey == providerKey, cancellationToken);
}

View File

@ -162,14 +162,4 @@ public class XhsHumanConfigRepository
FirstOrDefaultAsync(x => x.CustomerId == customerId, cancellationToken);
}
public class XhsAiProviderRepository
: OmsSqlSugarRepository<XhsAiProvider>, IXhsAiProviderRepository, IScopedDependency
{
public Task<XhsAiProvider?> GetByProviderKeyAsync(
int customerId,
string providerKey,
CancellationToken cancellationToken = default) =>
FirstOrDefaultAsync(x => x.CustomerId == customerId && x.ProviderKey == providerKey, cancellationToken);
}
public class XhsMediaRepository : OmsSqlSugarRepository<XhsMedia>, IXhsMediaRepository, IScopedDependency;

View File

@ -22,8 +22,8 @@ public class XhsRolePermissionSeedContributor(RoleService roleService) : IDataSe
"Xhs.Skills.Save",
"Xhs.Skills.Run",
"Xhs.HumanSettings.Save",
"Xhs.Ai.Use",
"Xhs.Ai.Save"
"System.Ai.Use",
"System.Ai.Save"
];
public async Task SeedAsync()