MCI18n/AI/I18nChatClient.cs

146 lines
4.7 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using OpenAI;
using OpenAI.Chat;
using System;
using System.ClientModel;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MCI18n.AI
{
internal class I18nChatClient
{
/// <summary>
/// 火山方舟API Key
/// </summary>
private string API_KEY = "API_KEY";
private string API_ENDPOINT = "https://ark.cn-beijing.volces.com/api/v3";
private readonly ChatClient _client;
// 使用信号量限制并发请求数
private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(2, 3); // 最多2个并发请求可根据API限制调整
// 重试次数和延迟
private const int MaxRetries = 3;
private static readonly TimeSpan InitialRetryDelay = TimeSpan.FromSeconds(1);
public I18nChatClient(string modelName)
{
_client = new ChatClient(modelName, new ApiKeyCredential(API_KEY), new OpenAIClientOptions
{
Endpoint = new Uri(API_ENDPOINT),
NetworkTimeout = TimeSpan.FromSeconds(20d)
});
}
private string SystemPrompt = @"
你是一个minecraft相关的语言翻译机器人。
你需要翻译用户提供的文本到指定的目标语言。
源语言通常是英文。
你只需要翻译文本,禁止解释或提供额外信息。
如果存在多种解释或是含义只需要给出最贴近Minecraft与社区Mod相关语言的一个。
被{}包裹的内容保留原文与位置。
";
private string Prompt = @"
目标语言:{0}
用户提供的文本:
{1}
";
public string Translate(string text, string targetLanguage)
{
try
{
_semaphore.Wait(); // 获取信号量
try
{
var quest = string.Format(Prompt, targetLanguage, text);
var response = _client.CompleteChat(
ChatMessage.CreateSystemMessage(SystemPrompt),
ChatMessage.CreateUserMessage($"{quest}")
);
if (!string.IsNullOrWhiteSpace(response.Value.Content[0].Text))
{
return response.Value.Content[0].Text;
}
else
{
throw new Exception("No response from translation model.");
}
}
finally
{
_semaphore.Release(); // 释放信号量
}
}
catch (Exception ex)
{
throw;
}
}
public async Task<string> TranslateAsync(string text, string targetLanguage)
{
int retries = 0;
TimeSpan delay = InitialRetryDelay;
while (true)
{
try
{
await _semaphore.WaitAsync(); // 异步获取信号量
try
{
var quest = string.Format(Prompt, targetLanguage, text);
var response = await _client.CompleteChatAsync(
ChatMessage.CreateSystemMessage(SystemPrompt),
ChatMessage.CreateUserMessage($"{quest}")
);
if (!string.IsNullOrWhiteSpace(response.Value.Content[0].Text))
{
return response.Value.Content[0].Text;
}
else
{
throw new Exception("No response from translation model.");
}
}
finally
{
_semaphore.Release(); // 释放信号量
}
}
catch (ClientResultException ex) when (ex.Status == 429 && retries < MaxRetries)
{
// 针对429错误特殊处理采用退避策略
retries++;
await Task.Delay(delay);
delay = TimeSpan.FromMilliseconds(delay.TotalMilliseconds * 2); // 指数退避
continue; // 重试请求
}
catch (Exception ex)
{
throw;
}
break; // 如果成功或者非429错误退出循环
}
// 这里不会被执行到,只是为了满足编译器要求
throw new Exception("Unexpected code path");
}
}
}