This commit is contained in:
bibabo 2024-07-12 16:42:19 +08:00
commit 4fe894fb6f
10 changed files with 256 additions and 29 deletions

View File

@ -13,6 +13,7 @@ using System.Net.Http.Json;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Serialization;
using HuanMeng.MiaoYu.Code.Chat.Claude.Model;
namespace HuanMeng.MiaoYu.Code.Chat.Claude
{
@ -21,6 +22,13 @@ namespace HuanMeng.MiaoYu.Code.Chat.Claude
/// </summary>
public class ClaudeChat(ClaudeChatConfig claudeChatConfig, IHttpClientFactory factory) : IChat
{
/// <summary>
///
/// </summary>
/// <param name="chatParams"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="NotImplementedException"></exception>
public async Task<BaseChatInfo> MessagesAsync(BaseChatParams chatParams)
{
var claudeChatChatParams = chatParams as ClaudeChatChatParams;
@ -52,20 +60,71 @@ namespace HuanMeng.MiaoYu.Code.Chat.Claude
};
string json = JsonConvert.SerializeObject(chatParams, settings);
var content = new StringContent(json, Encoding.UTF8, "application/json");
//HttpClientHandler httpClientHandler = new HttpClientHandler();
//HttpContent httpContent = new JsonContent();
var response = await httpClient.PostAsync(claudeChatConfig.RequestUrl, content);
if (response.IsSuccessStatusCode)
{
var chatInfo = response.Content.ReadFromJsonAsync<BaseChatInfo?>();
var chatInfo = await response.Content.ReadFromJsonAsync<ClaudeChatResponse?>();
return chatInfo;
}
}
throw new NotImplementedException();
return null;
}
public IAsyncEnumerable<BaseChatStream> MessagesStreamAsync(BaseChatParams chatParams)
public async IAsyncEnumerable<string> MessagesStreamAsync(BaseChatParams chatParams)
{
throw new NotImplementedException();
var claudeChatChatParams = chatParams as ClaudeChatChatStreamParams;
if (claudeChatChatParams == null)
{
throw new ArgumentException("参数异常");
}
//添加默认值
if (claudeChatChatParams.MaxTokens == 0)
{
claudeChatChatParams.MaxTokens = claudeChatConfig.MaxTokens;
}
claudeChatChatParams.Stream = true;
//添加默认值
if (!string.IsNullOrEmpty(claudeChatChatParams.Model))
{
claudeChatChatParams.Model = claudeChatChatParams.Model;
}
//去线程池里拿http线程
using (var httpClient = factory.CreateClient())
{
// 设置请求头
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Add("x-api-key", claudeChatConfig.ApiKey);
httpClient.DefaultRequestHeaders.Add("anthropic-version", claudeChatConfig.AnthropicVersion);
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
string json = JsonConvert.SerializeObject(chatParams, settings);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(claudeChatConfig.RequestUrl, content);
if (response.IsSuccessStatusCode)
{
var chatInfo = await response.Content.ReadFromJsonAsync<ClaudeChatStreamResponse?>();
if (chatInfo?.Type == "message_delta")
{
claudeChatChatParams.OutCharResponse.Usage.OutputTokens = chatInfo.Usage?.OutputTokens ?? 0;
}
else if (chatInfo?.Type == "content_block_start")
{
claudeChatChatParams.OutCharResponse = chatInfo?.Message ?? new ClaudeChatResponse();
}
else if (chatInfo?.Type == "content_block_delta")
{
var text = chatInfo?.Delta?.Text ?? "";
if (!string.IsNullOrEmpty(text))
{
yield return text;
}
}
claudeChatChatParams.OutObj.Add(chatInfo);
}
}
}
}
}

View File

@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat.Claude
{
/// <summary>
/// Claude3 请求的参数
/// Claude3 请求的参数
/// </summary>
public class ClaudeChatChatParams : BaseClaudeChatChatParams
{

View File

@ -0,0 +1,31 @@
using HuanMeng.MiaoYu.Code.Chat.Claude.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat.Claude
{
/// <summary>
/// 实时流
/// </summary>
public class ClaudeChatChatStreamParams : BaseClaudeChatChatParams
{
/// <summary>
/// 视频流
/// </summary>
public bool Stream { get; set; }
/// <summary>
/// 返回消息内容
/// </summary>
public ClaudeChatResponse OutCharResponse { get; set; }
/// <summary>
///
/// </summary>
public List<object> OutObj { get; set; }
}
}

View File

@ -1,20 +0,0 @@
using HuanMeng.MiaoYu.Code.Chat.Contract;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat.Claude
{
/// <summary>
/// 返回内容
/// </summary>
public class ClaudeChatInfo : BaseChatInfo
{
}
}

View File

@ -0,0 +1,28 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat.Claude.Model
{
/// <summary>
/// 消息内容
/// </summary>
public class ClaudeChatContent
{
/// <summary>
/// 内容类型
/// </summary>
[JsonProperty("type")]
public string Type { get; set; }
/// <summary>
/// 文本内容
/// </summary>
[JsonProperty("text")]
public string Text { get; set; }
}
}

View File

@ -0,0 +1,60 @@
using HuanMeng.MiaoYu.Code.Chat.Contract;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat.Claude.Model
{
/// <summary>
/// 返回内容
/// </summary>
public class ClaudeChatResponse : BaseChatInfo
{
/// <summary>
/// 消息 ID
/// </summary>
[JsonProperty("id")]
public string Id { get; set; }
/// <summary>
/// 模型
/// </summary>
[JsonProperty("model")]
public string Model { get; set; }
/// <summary>
/// 消息类型
/// </summary>
[JsonProperty("type")]
public string Type { get; set; }
/// <summary>
/// 角色
/// </summary>
[JsonProperty("role")]
public string Role { get; set; }
/// <summary>
/// 消息内容
/// </summary>
[JsonProperty("content")]
public ClaudeChatContent[] Content { get; set; }
/// <summary>
/// 停止原因
/// </summary>
[JsonProperty("stop_reason")]
public string StopReason { get; set; }
/// <summary>
/// 使用情况
/// </summary>
[JsonProperty("usage")]
public ClaudeChatUsage Usage { get; set; }
}
}

View File

@ -0,0 +1,41 @@
using HuanMeng.MiaoYu.Code.Chat.Contract;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat.Claude.Model
{
/// <summary>
///
/// </summary>
public class ClaudeChatStreamResponse : BaseChatStream
{
public int? Index { get; set; }
/// <summary>
/// 类型
/// </summary>
public string Type { get; set; }
/// <summary>
/// 内容
/// </summary>
public ClaudeChatContent? Delta { get; set; }
/// <summary>
/// 结尾
/// </summary>
public ClaudeChatResponse? Message { get; set; }
/// <summary>
/// 使用情况
/// </summary>
[JsonProperty("usage")]
public ClaudeChatUsage Usage { get; set; }
}
//delta
}

View File

@ -0,0 +1,28 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat.Claude.Model
{
/// <summary>
/// 使用情况
/// </summary>
public class ClaudeChatUsage
{
/// <summary>
/// 输入的 token 数量
/// </summary>
[JsonProperty("input_tokens")]
public int InputTokens { get; set; }
/// <summary>
/// 输出的 token 数量
/// </summary>
[JsonProperty("output_tokens")]
public int OutputTokens { get; set; }
}
}

View File

@ -23,6 +23,6 @@ namespace HuanMeng.MiaoYu.Code.Chat.Contract
/// </summary>
/// <param name="chatParams"></param>
/// <returns></returns>
IAsyncEnumerable<BaseChatStream> MessagesStreamAsync(BaseChatParams chatParams);
IAsyncEnumerable<string> MessagesStreamAsync(BaseChatParams chatParams);
}
}

View File

@ -7,7 +7,7 @@ var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddHttpContextAccessor(); //添加httpContext注入访问
builder.Services.AddControllers();
builder.Services.AddHttpClient();
//注入数据库
builder.Services.AddDbContext<TextGenerationTestContext>((options) =>
{