feat: 完成意心ai agent
This commit is contained in:
@@ -1,8 +1,15 @@
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||
|
||||
public class SessionCreateAndUpdateInput
|
||||
{
|
||||
public string SessionTitle { get; set; }
|
||||
public string SessionContent { get; set; }
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 会话类型
|
||||
/// </summary>
|
||||
public SessionTypeEnum SessionType { get; set; } = SessionTypeEnum.Chat;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||
|
||||
@@ -7,4 +8,9 @@ public class SessionDto : FullAuditedEntityDto<Guid>
|
||||
public string SessionTitle { get; set; }
|
||||
public string SessionContent { get; set; }
|
||||
public string Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 会话类型
|
||||
/// </summary>
|
||||
public SessionTypeEnum SessionType { get; set; }
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
using Yi.Framework.Ddd.Application.Contracts;
|
||||
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||
using Yi.Framework.Ddd.Application.Contracts;
|
||||
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||
|
||||
public class SessionGetListInput:PagedAllResultRequestDto
|
||||
public class SessionGetListInput : PagedAllResultRequestDto
|
||||
{
|
||||
public string? SessionTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 会话类型
|
||||
/// </summary>
|
||||
public SessionTypeEnum? SessionType { get; set; }
|
||||
}
|
||||
@@ -84,7 +84,8 @@ public class SessionService : CrudAppService<SessionAggregateRoot, SessionDto, G
|
||||
RefAsync<int> total = 0;
|
||||
var userId = CurrentUser.GetId();
|
||||
var entities = await _repository._DbQueryable
|
||||
.Where(x=>x.UserId == userId)
|
||||
.Where(x => x.UserId == userId)
|
||||
.WhereIF(input.SessionType.HasValue, x => x.SessionType == input.SessionType!.Value)
|
||||
.OrderByDescending(x => x.Id)
|
||||
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
||||
return new PagedResultDto<SessionDto>(total, entities.Adapt<List<SessionDto>>());
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// 会话类型枚举
|
||||
/// </summary>
|
||||
public enum SessionTypeEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 普通聊天
|
||||
/// </summary>
|
||||
Chat = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Agent智能体
|
||||
/// </summary>
|
||||
Agent = 1
|
||||
}
|
||||
@@ -75,10 +75,7 @@ public class AnthropicChatCompletionsService(
|
||||
{
|
||||
Guid errorId = Guid.NewGuid();
|
||||
var error = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
||||
logger.LogError("Anthropic非流式对话异常 请求地址:{Address},ErrorId:{errorId}, StatusCode: {StatusCode.GetHashCode()} Response: {Response}",
|
||||
options.Endpoint,
|
||||
errorId,
|
||||
response.StatusCode, error);
|
||||
logger.LogError($"Anthropic非流式对话异常 请求地址:{options.Endpoint},ErrorId:{errorId}, StatusCode: {response.StatusCode.GetHashCode()}, Response: {error}");
|
||||
|
||||
throw new Exception( $"恭喜你运气爆棚遇到了错误,尊享包对话异常:StatusCode【{response.StatusCode.GetHashCode()}】,ErrorId【{errorId}】");
|
||||
}
|
||||
@@ -125,10 +122,7 @@ public class AnthropicChatCompletionsService(
|
||||
{
|
||||
Guid errorId = Guid.NewGuid();
|
||||
var error = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
||||
logger.LogError("Anthropic流式对话异常 请求地址:{Address},ErrorId:{errorId}, StatusCode: {StatusCode.GetHashCode()} Response: {Response}",
|
||||
options.Endpoint,
|
||||
errorId,
|
||||
response.StatusCode, error);
|
||||
logger.LogError($"Anthropic流式对话异常 请求地址:{options.Endpoint},ErrorId:{errorId}, StatusCode: {response.StatusCode.GetHashCode()}, Response: {error}");
|
||||
|
||||
throw new Exception( $"恭喜你运气爆棚遇到了错误,尊享包对话异常:StatusCode【{response.StatusCode.GetHashCode()}】,ErrorId【{errorId}】");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using SqlSugar;
|
||||
using Volo.Abp.Domain.Entities.Auditing;
|
||||
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.Entities.Chat;
|
||||
|
||||
@@ -9,8 +10,13 @@ public class SessionAggregateRoot : FullAuditedAggregateRoot<Guid>
|
||||
{
|
||||
public Guid UserId { get; set; }
|
||||
public string SessionTitle { get; set; }
|
||||
|
||||
|
||||
[SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString)]
|
||||
public string SessionContent { get; set; }
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 会话类型:0-普通聊天,1-Agent智能体
|
||||
/// </summary>
|
||||
public SessionTypeEnum SessionType { get; set; } = SessionTypeEnum.Chat;
|
||||
}
|
||||
@@ -1,16 +1,199 @@
|
||||
using System.ComponentModel;
|
||||
using ModelContextProtocol.Server;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Yi.Framework.AiHub.Domain.Shared.Attributes;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.Mcp;
|
||||
|
||||
[YiAgentTool]
|
||||
public class OnlineSearchTool:ISingletonDependency
|
||||
public class OnlineSearchTool : ISingletonDependency
|
||||
{
|
||||
[YiAgentTool("联网搜索"),DisplayName("OnlineSearch"), Description("进行在线搜索")]
|
||||
public string OnlineSearch(string keyword)
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly ILogger<OnlineSearchTool> _logger;
|
||||
private readonly string _baiduApiKey;
|
||||
private const string BaiduSearchUrl = "https://qianfan.baidubce.com/v2/ai_search/web_search";
|
||||
|
||||
public OnlineSearchTool(
|
||||
IHttpClientFactory httpClientFactory,
|
||||
ILogger<OnlineSearchTool> logger,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
return "奥德赛第一中学学生会会长是:郭老板";
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_logger = logger;
|
||||
_baiduApiKey = configuration["BaiduSearch:ApiKey"] ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
[YiAgentTool("联网搜索"), DisplayName("OnlineSearch"), Description("进行在线搜索,获取最新的网络信息")]
|
||||
public async Task<string> OnlineSearch(string keyword)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(keyword))
|
||||
{
|
||||
return "搜索关键词不能为空";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
|
||||
// 构建请求体
|
||||
var requestBody = new BaiduSearchRequest
|
||||
{
|
||||
Messages = new List<BaiduSearchMessage>
|
||||
{
|
||||
new() { Role = "user", Content = keyword }
|
||||
}
|
||||
};
|
||||
|
||||
var jsonContent = JsonSerializer.Serialize(requestBody, BaiduJsonContext.Default.BaiduSearchRequest);
|
||||
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
|
||||
|
||||
// 设置请求头
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, BaiduSearchUrl)
|
||||
{
|
||||
Content = content
|
||||
};
|
||||
request.Headers.Add("Authorization", $"Bearer {_baiduApiKey}");
|
||||
|
||||
// 发送请求
|
||||
var response = await client.SendAsync(request);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var errorContent = await response.Content.ReadAsStringAsync();
|
||||
_logger.LogError("百度搜索接口调用失败: {StatusCode}, {Error}", response.StatusCode, errorContent);
|
||||
return $"搜索失败: {response.StatusCode}";
|
||||
}
|
||||
|
||||
var responseJson = await response.Content.ReadAsStringAsync();
|
||||
var searchResult = JsonSerializer.Deserialize(responseJson, BaiduJsonContext.Default.BaiduSearchResponse);
|
||||
|
||||
if (searchResult?.References == null || searchResult.References.Count == 0)
|
||||
{
|
||||
return "未找到相关搜索结果";
|
||||
}
|
||||
|
||||
// 格式化搜索结果返回给AI
|
||||
return FormatSearchResults(searchResult.References);
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
_logger.LogError(ex, "百度搜索网络请求异常");
|
||||
return "搜索服务暂时不可用,请稍后重试";
|
||||
}
|
||||
catch (TaskCanceledException ex)
|
||||
{
|
||||
_logger.LogError(ex, "百度搜索请求超时");
|
||||
return "搜索请求超时,请稍后重试";
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
_logger.LogError(ex, "百度搜索结果解析失败");
|
||||
return "搜索结果解析失败";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "百度搜索发生未知异常");
|
||||
return "搜索发生异常,请稍后重试";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 格式化搜索结果
|
||||
/// </summary>
|
||||
private string FormatSearchResults(List<BaiduSearchReference> references)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("搜索结果:");
|
||||
sb.AppendLine();
|
||||
|
||||
var count = 0;
|
||||
foreach (var item in references.Take(10)) // 最多返回10条
|
||||
{
|
||||
count++;
|
||||
sb.AppendLine($"【{count}】{item.Title}");
|
||||
sb.AppendLine($"来源:{item.Website} | 时间:{item.Date}");
|
||||
sb.AppendLine($"摘要:{item.Snippet}");
|
||||
sb.AppendLine($"链接:{item.Url}");
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#region 百度搜索 DTO
|
||||
|
||||
/// <summary>
|
||||
/// 百度搜索请求
|
||||
/// </summary>
|
||||
public class BaiduSearchRequest
|
||||
{
|
||||
[JsonPropertyName("messages")]
|
||||
public List<BaiduSearchMessage> Messages { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 百度搜索消息
|
||||
/// </summary>
|
||||
public class BaiduSearchMessage
|
||||
{
|
||||
[JsonPropertyName("role")]
|
||||
public string Role { get; set; } = "user";
|
||||
|
||||
[JsonPropertyName("content")]
|
||||
public string Content { get; set; } = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 百度搜索响应
|
||||
/// </summary>
|
||||
public class BaiduSearchResponse
|
||||
{
|
||||
[JsonPropertyName("request_id")]
|
||||
public string? RequestId { get; set; }
|
||||
|
||||
[JsonPropertyName("references")]
|
||||
public List<BaiduSearchReference>? References { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 百度搜索结果项
|
||||
/// </summary>
|
||||
public class BaiduSearchReference
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
public string? Url { get; set; }
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public string? Title { get; set; }
|
||||
|
||||
[JsonPropertyName("date")]
|
||||
public string? Date { get; set; }
|
||||
|
||||
[JsonPropertyName("snippet")]
|
||||
public string? Snippet { get; set; }
|
||||
|
||||
[JsonPropertyName("website")]
|
||||
public string? Website { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region JSON 序列化上下文
|
||||
|
||||
[JsonSerializable(typeof(BaiduSearchRequest))]
|
||||
[JsonSerializable(typeof(BaiduSearchResponse))]
|
||||
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
|
||||
internal partial class BaiduJsonContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
Reference in New Issue
Block a user