using VideoAnalysisCore.Common;
using System.Net.Http.Headers;
using System.Text;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using System.Net.Http;
namespace VideoAnalysisCore.AICore.ChatGPT.KIMI
{
///
/// https://platform.moonshot.cn/docs/api-reference
///
public class MoonshotClient
{
private readonly ILogger _logger;
private readonly IHttpClientFactory _httpClientFactory;
public MoonshotClient(ILogger logger, IHttpClientFactory httpClientFactory)
{
_logger = logger;
_httpClientFactory = httpClientFactory;
}
///
/// list models
///
///
public async Task ListModels()
{
var response = await GetAsync("/v1/models");
return await ParseResp(response);
}
///
/// Chat
///
///
/// Return HttpResponseMessage for SSE
public async Task Chat(string requestBody)
{
return await PostJsonStreamAsync("/v1/chat/completions", requestBody);
}
///
/// Chat
///
///
/// Return HttpResponseMessage for SSE
public async Task Chat(ChatReq chatReq)
{
var requestBody = System.Text.Json.JsonSerializer.Serialize(chatReq);
return await PostJsonStreamAsync("/v1/chat/completions", requestBody);
}
///
/// Get as timate token count
///
public async Task GetAsTiMateTokenCount(string chatReqText)
{
var response = await PostJsonAsync("/v1/tokenizers/estimate-token-count", chatReqText);
var responseText = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var responseObj = JToken.Parse(responseText);
return responseObj?["data"]?["total_tokens"]?.ToObject();
}
var error = System.Text.Json.JsonSerializer.Deserialize(responseText);
_logger.LogError($"{error?.error?.type}: {error?.error?.message}");
throw new Exception($"{error?.error.type}: {error?.error.message}");
}
///
/// Get as timate token count
///
///
///
public async Task GetAsTiMateTokenCount(ChatReq chatReq)
{
var chatReqText =System.Text.Json.JsonSerializer.Serialize(chatReq);
return await GetAsTiMateTokenCount(chatReqText);
}
///
/// List files
///
public virtual async Task ListFiles()
{
var response = await GetAsync("/v1/files");
return await ParseResp(response);
}
///
/// Upload file
///
public virtual async Task UploadFile(string filePath)
{
if (!File.Exists(filePath))
{
throw new FileNotFoundException($"{filePath} not found");
}
var client = _httpClientFactory.CreateClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ApiKey);
var request = new HttpRequestMessage(HttpMethod.Post, $"{Host}/v1/files");
var content = new MultipartFormDataContent
{
{ new StreamContent(File.OpenRead(filePath)), "file", filePath }
};
request.Content = content;
var response = await client.SendAsync(request);
return await ParseResp(response);
}
///
/// Upload file stream
///
public virtual async Task UploadFileStream(Stream stream, string fileName)
{
var client = _httpClientFactory.CreateClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ApiKey);
var request = new HttpRequestMessage(HttpMethod.Post, $"{Host}/v1/files");
var content = new MultipartFormDataContent
{
{ new StreamContent(stream), "file", fileName }
};
request.Content = content;
var response = await client.SendAsync(request);
return await ParseResp(response);
}
///
/// Get file content
///
public virtual async Task GetFileContent(string fileId)
{
var response = await GetAsync($"/v1/files/{fileId}/content");
return await ParseResp(response);
}
private async Task GetAsync(string path)
{
var client = _httpClientFactory.CreateClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ApiKey);
return await client.GetAsync(Host + path);
}
private async Task PostJsonAsync(string path, string json)
{
var client = _httpClientFactory.CreateClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ApiKey);
return await client.PostAsync(Host + path, new StringContent(json, Encoding.UTF8, "application/json"));
}
private async Task PostJsonStreamAsync(string path, string json)
{
var client = _httpClientFactory.CreateClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ApiKey);
var request = ToHttpRequest(path);
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
return await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
}
private HttpRequestMessage ToHttpRequest(string path)
{
var request = new HttpRequestMessage();
var uriBuilder = new UriBuilder(Host + path);
request.RequestUri = uriBuilder.Uri;
request.Method = new HttpMethod("POST");
request.Headers.Host = new Uri(Host).Host;
return request;
}
///
/// Parse response
///
private async Task ParseResp(HttpResponseMessage response)
{
var responseText = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
return System.Text.Json.JsonSerializer.Deserialize(responseText) ?? default;
}
var error = System.Text.Json.JsonSerializer.Deserialize(responseText);
_logger.LogError($"{error?.error.type}: {error?.error.message}");
throw new Exception($"{error?.error.type}: {error?.error.message}");
}
private static string _host = "https://api.moonshot.cn";
public static string Host
{
get
{
if (string.IsNullOrEmpty(_host) && !string.IsNullOrEmpty(AppCommon.Config.ChatGpt.KIMI.Host))
{
_host = AppCommon.Config.ChatGpt.KIMI.Host ?? "";
}
return _host;
}
set
{
_host = value;
}
}
private static string _apiKey = "sk_";
public static string ApiKey
{
get
{
if (string.IsNullOrEmpty(_apiKey) && !string.IsNullOrEmpty(AppCommon.Config.ChatGpt.KIMI.ApiKey))
{
_apiKey = AppCommon.Config.ChatGpt.KIMI.ApiKey ?? "";
}
return _apiKey;
}
set
{
_apiKey = value;
}
}
}
}