网站首页 网站源码
using Dpz.Core.Service.Network;
using Dpz.Core.Service.Network.Models;
using Dpz.Core.Service.Network.Models.XunFei;
using Dpz.Core.Web.Pager;
using Microsoft.AspNetCore.SignalR;
namespace Dpz.Core.Web.Library.Hub;
public class RobotChatHub(
ILogger<RobotChatHub> logger,
IChatRecordService chatRecordService,
IConfiguration configuration,
XunFeiService xunFeiService,
AnalyzeService analyzeService
) : Microsoft.AspNetCore.SignalR.Hub
{
public async Task SendMessage(string question)
{
var sessionId = Guid.NewGuid().ToString("N");
var httpContext = Context.GetHttpContext();
var userId =
Context.User?.IsLogin() == true
? Context.User.GetIdentity()?.Id
: httpContext?.Request.Cookies[Program.AuthorizeCookieName + ".SessionId"];
if (!string.IsNullOrEmpty(userId))
{
sessionId = userId;
}
var request = await GetXunFeiRequestAsync(sessionId, question, Context.User);
ResponseResult<List<XunFeiResponse?>> responseResult;
try
{
responseResult = await xunFeiService.ChatAsync(request);
if (!responseResult.Success)
{
await Clients.Caller.SendCoreAsync(
"SystemError",
[XunFeiReceiverUser(ErrorMessage(responseResult.Message))]
);
return;
}
}
catch (Exception ex)
{
await Clients.Caller.SendCoreAsync(
"SystemError",
[XunFeiReceiverUser(ErrorMessage(ex.Message))]
);
logger.LogError(ex, "API调用出错");
return;
}
var message = "";
if (responseResult.Data != null)
{
var messageSb = new StringBuilder();
responseResult.Data.ForEach(x =>
messageSb.Append(x?.Payload?.Choices?.Text?.FirstOrDefault()?.Content ?? "")
);
message = messageSb.ToString();
await Clients.Caller.SendCoreAsync("Answer", [XunFeiReceiverUser(message)]);
}
if (Context.User.IsLogin())
{
var sender = Context.User?.GetIdentity();
if (sender == null)
{
return;
}
var receiver = XunFeiUser();
await chatRecordService.SaveFriendRecordAsync(sender, question, receiver);
await chatRecordService.SaveRobotRecordAsync(receiver, message, message);
}
}
public async Task SendMessageToChatGpt(string content)
{
if (string.IsNullOrWhiteSpace(content))
{
await Clients.Caller.SendCoreAsync("SystemError", [ChatGptReceiverUser("请输入内容")]);
return;
}
if (!Context.User.IsLogin())
{
await Clients.Caller.SendCoreAsync("SystemError", [ChatGptReceiverUser("尚未登录")]);
return;
}
try
{
var sender = Context.User?.GetIdentity() ?? throw new BusinessException("尚未登录");
var receiver = ChatGptUser();
await chatRecordService.SaveFriendRecordAsync(sender, content, receiver);
var records = await chatRecordService.GetFriendRecordAsync(
sender.Id,
ApplicationTools.ChatGptUserId,
1,
4
);
var messages = records
.OrderBy(x => x.SendTime)
.Select(x => new ChatMessage
{
Role = x.Sender?.Id == ApplicationTools.ChatGptUserId ? "assistant" : "user",
Message = x.Message,
})
.ToList();
//messages.Add(new ChatMessage { Role = "user", Message = content });
var result = await analyzeService.ChatAsync(messages);
if (!result.Success)
{
await Clients.Caller.SendCoreAsync(
"SystemError",
[ChatGptReceiverUser(ErrorMessage(result.Message))]
);
}
var sendAnswerContent = result.Data ?? "";
await Clients.Caller.SendCoreAsync("Answer", [ChatGptReceiverUser(sendAnswerContent)]);
await chatRecordService.SaveFriendRecordAsync(receiver, sendAnswerContent, sender);
}
catch (Exception e)
{
await Clients.Caller.SendCoreAsync(
"SystemError",
[ChatGptReceiverUser(ErrorMessage(e.Message))]
);
}
}
private async Task<XunFeiRequest> GetXunFeiRequestAsync(
string uid,
string question,
ClaimsPrincipal? user
)
{
var userInfo = user?.GetIdentity();
IPagedList<VmChatRecord> chatRecords = PagedList<VmChatRecord>.Empty();
if (userInfo != null)
{
chatRecords = await chatRecordService.GetFriendRecordAsync(
userInfo.Id,
XunFeiUserId,
1,
4
);
}
var messages = chatRecords
.OrderBy(x => x.SendTime)
.Select(x => new XunFeiRequestText
{
Content = x.Message,
Role = x.Sender?.Id == XunFeiUserId ? "assistant" : "user",
})
.ToList();
messages.Add(new XunFeiRequestText { Content = question, Role = "user" });
return new XunFeiRequest
{
Header = new XunFeiRequestHeader
{
AppId = configuration["XunFei:AppId"] ?? throw new Exception("AppId is null"),
Uid = uid,
},
Parameter = new XunFeiRequestParameter { Chat = new XunFeiRequestChat() },
Payload = new XunFeiRequestPayload
{
Message = new XunFeiRequestMessage { Text = messages },
},
};
}
private object XunFeiReceiverUser(string message)
{
return new
{
id = "kefu",
avatar = $"{configuration["CDNBaseAddress"]}/images/ai.jpg",
username = "星火认知大模型",
type = "friend",
content = message,
mine = false,
};
}
private object ChatGptReceiverUser(string message)
{
return new
{
id = ApplicationTools.ChatGptUserId,
avatar = $"{configuration["CDNBaseAddress"]}/images/ChatGPT.ico",
username = "ChatGPT",
type = "friend",
content = message,
mine = false,
};
}
private static string XunFeiUserId => "kefu";
private VmUserInfo XunFeiUser()
{
return new VmUserInfo
{
Avatar = $"{configuration["CDNBaseAddress"]}/images/ai.jpg",
Enable = true,
Id = XunFeiUserId,
Key = "",
LastAccessTime = DateTime.Now,
Name = "星火认知大模型",
Permissions = null,
};
}
private VmUserInfo ChatGptUser()
{
return new VmUserInfo
{
Avatar = $"{configuration["CDNBaseAddress"]}/images/ChatGPT.ico",
Enable = true,
Id = ApplicationTools.ChatGptUserId,
Key = "",
LastAccessTime = DateTime.Now,
Name = "ChatGPT",
Permissions = null,
};
}
private static string ErrorMessage(string? message)
{
return $"调用API出错,错误信息:<span style='color:red;'>{(message ?? "Call API fail")}</span>";
}
public override Task OnConnectedAsync()
{
var sessionId = Context
.GetHttpContext()
?.Request.Cookies[Program.AuthorizeCookieName + ".SessionId"];
Clients.Caller.SendCoreAsync("Connected", ["websocket connected.", sessionId]);
return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception? exception)
{
var sessionId = Context
.GetHttpContext()
?.Request.Cookies[Program.AuthorizeCookieName + ".SessionId"];
Clients.Caller.SendCoreAsync("Disconnected", ["websocket disconnected.", sessionId]);
if (exception != null)
{
logger.LogError(exception, "signalR disconnected");
}
return base.OnDisconnectedAsync(exception);
}
}
上述代码定义了一个 SignalR Hub 类 RobotChatHub
,用于处理与聊天机器人(如讯飞和 ChatGPT)之间的实时消息交互。以下是代码的主要功能和结构的详细解释:
RobotChatHub
类的构造函数接受多个依赖项,包括日志记录器、聊天记录服务、配置、讯飞服务和分析服务。这些依赖项用于处理聊天请求、记录聊天记录和与外部服务交互。
SendMessage
方法GetXunFeiRequestAsync
方法构建请求。xunFeiService.ChatAsync
方法与讯飞 API 交互。SendMessageToChatGpt
方法analyzeService.ChatAsync
方法与 ChatGPT 交互。GetXunFeiRequestAsync
方法XunFeiRequest
对象。XunFeiReceiverUser
和 ChatGptReceiverUser
方法用于格式化发送给客户端的消息,包含用户的头像、用户名和消息内容。XunFeiUser
和 ChatGptUser
方法返回代表讯飞和 ChatGPT 的用户信息对象。ErrorMessage
方法用于格式化错误信息,以便在客户端显示。OnConnectedAsync
和 OnDisconnectedAsync
方法用于处理用户连接和断开连接事件,记录连接状态并向客户端发送相应的消息。RobotChatHub
类实现了一个实时聊天系统的核心功能,允许用户与讯飞和 ChatGPT 进行交互。它处理消息的发送和接收,记录聊天记录,并在出现错误时提供反馈。通过 SignalR,用户可以实时接收来自聊天机器人的响应。