generated from karashiiro/DalamudPluginProjectTemplate
-
-
Notifications
You must be signed in to change notification settings - Fork 18
/
ChatGPTTranslator.cs
128 lines (106 loc) · 5.94 KB
/
ChatGPTTranslator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// <copyright file="ChatGPTTranslator.cs" company="lokinmodar">
// Copyright (c) lokinmodar. All rights reserved.
// Licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License license.
// </copyright>
using System;
using System.ClientModel;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Dalamud.Plugin.Services;
using OpenAI;
using OpenAI.Chat;
namespace Echoglossian
{
public class ChatGPTTranslator : ITranslator
{
private readonly ChatClient chatClient;
private readonly IPluginLog pluginLog;
private readonly string model;
private float temperature;
private Dictionary<string, string> translationCache = new Dictionary<string, string>();
public ChatGPTTranslator(IPluginLog pluginLog, string baseUrl = "https://api.openai.com/v1", string apiKey = "", string model = "gpt-4o-mini", float temperature = 0.1f)
{
this.pluginLog = pluginLog;
this.model = model;
this.temperature = temperature;
pluginLog.Debug($"ChatGPTTranslator: {baseUrl}, {apiKey[..20]}***{apiKey[^5..]}, {temperature}");
if (string.IsNullOrWhiteSpace(apiKey))
{
this.pluginLog.Warning("API Key is empty or invalid. ChatGPT transaltion will not be available.");
this.chatClient = null;
}
else
{
try
{
var clientOptions = new OpenAIClientOptions
{
Endpoint = new Uri(baseUrl),
};
pluginLog.Debug($"ChatGPTTranslator: {string.Join(", ", clientOptions.GetType().GetProperties().Select(p => $"{p.Name}={p.GetValue(clientOptions)}"))}");
this.chatClient = new ChatClient(model, new ApiKeyCredential(apiKey), clientOptions);
}
catch (Exception ex)
{
this.pluginLog.Error($"Failed to initialize GPT ChatClient: {ex.Message}");
this.chatClient = null;
}
}
}
public string Translate(string text, string sourceLanguage, string targetLanguage)
{
return this.TranslateAsync(text, sourceLanguage, targetLanguage).GetAwaiter().GetResult();
}
public async Task<string> TranslateAsync(string text, string sourceLanguage, string targetLanguage)
{
if (this.chatClient == null)
{
return "[ChatGPT translation unavailable. Please check your API key.]";
}
string cacheKey = $"{text}_{sourceLanguage}_{targetLanguage}";
if (this.translationCache.TryGetValue(cacheKey, out string cachedTranslation))
{
return cachedTranslation;
}
string prompt = @$"As an expert translator and cultural localization specialist with deep knowledge of video game localization, your task is to translate dialogues from the game Final Fantasy XIV from {sourceLanguage} to {targetLanguage}. This is not just a translation, but a full localization effort tailored for the Final Fantasy XIV universe. Please adhere to the following guidelines:
1. Preserve the original tone, humor, personality, and emotional nuances of the dialogue, considering the unique style and atmosphere of Final Fantasy XIV.
2. Adapt idioms, cultural references, and wordplay to resonate naturally with native {targetLanguage} speakers while maintaining the fantasy RPG context.
3. Maintain consistency in character voices, terminology, and naming conventions specific to Final Fantasy XIV throughout the translation.
4. Avoid literal translations that may lose the original intent or impact, especially for game-specific terms or lore elements.
5. Ensure the translation flows naturally and reads as if it were originally written in {targetLanguage}, while staying true to the game's narrative style.
6. Consider the context and subtext of the dialogue, including any references to the game's lore, world, or ongoing storylines.
7. If a word, phrase, or name has been translated in a specific way, maintain that translation consistently unless the context demands otherwise, respecting established localization choices for Final Fantasy XIV.
8. Pay attention to formal/informal speech patterns and adjust accordingly for the target language and cultural norms, considering the speaker's role and status within the game world.
9. Be mindful of character limits or text box constraints that may be present in the game, adapting the translation to fit if necessary.
10. Preserve any game-specific jargon, spell names, or technical terms according to the official localization guidelines for Final Fantasy XIV in the target language.
Text to translate: ""{text}""
Please provide only the translated text in your response, without any explanations, additional comments, or quotation marks. Your goal is to create a localized version that captures the essence of the original Final Fantasy XIV dialogue while feeling authentic to {targetLanguage} speakers and seamlessly fitting into the game world.";
try
{
var chatCompletionOptions = new ChatCompletionOptions
{
Temperature = this.temperature,
};
var messages = new List<ChatMessage>
{
ChatMessage.CreateUserMessage(prompt),
};
ChatCompletion completion = await this.chatClient.CompleteChatAsync(messages, chatCompletionOptions);
string translatedText = completion.Content[0].Text.Trim();
translatedText = translatedText.Trim('"');
if (!string.IsNullOrEmpty(translatedText))
{
this.translationCache[cacheKey] = translatedText;
return translatedText;
}
}
catch (Exception ex)
{
this.pluginLog.Error($"Translation error: {ex.Message}");
return $"[Translation Error: {ex.Message}]";
}
return null;
}
}
}