mirror of
https://github.com/SubtitleEdit/subtitleedit.git
synced 2024-11-25 04:33:04 +01:00
parent
31ed11f60a
commit
f4f61f20ba
89
src/libse/AutoTranslate/LmStudioTranslate.cs
Normal file
89
src/libse/AutoTranslate/LmStudioTranslate.cs
Normal file
@ -0,0 +1,89 @@
|
||||
using Nikse.SubtitleEdit.Core.Common;
|
||||
using Nikse.SubtitleEdit.Core.SubtitleFormats;
|
||||
using Nikse.SubtitleEdit.Core.Translate;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.AutoTranslate
|
||||
{
|
||||
public class LmStudioTranslate : IAutoTranslator
|
||||
{
|
||||
private HttpClient _httpClient;
|
||||
|
||||
public static string StaticName { get; set; } = "LM Studio (local ChatGPT)";
|
||||
public string Name => StaticName;
|
||||
public string Url => "https://lmstudio.ai/";
|
||||
public string Error { get; set; }
|
||||
public int MaxCharacters => 1000;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_httpClient?.Dispose();
|
||||
_httpClient = new HttpClient();
|
||||
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
|
||||
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation("accept", "application/json");
|
||||
_httpClient.BaseAddress = new Uri(Configuration.Settings.Tools.LmStudioApiUrl.TrimEnd('/'));
|
||||
_httpClient.Timeout = TimeSpan.FromMinutes(15);
|
||||
}
|
||||
|
||||
public List<TranslationPair> GetSupportedSourceLanguages()
|
||||
{
|
||||
return ChatGptTranslate.ListLanguages();
|
||||
}
|
||||
|
||||
public List<TranslationPair> GetSupportedTargetLanguages()
|
||||
{
|
||||
return ChatGptTranslate.ListLanguages();
|
||||
}
|
||||
|
||||
public async Task<string> Translate(string text, string sourceLanguageCode, string targetLanguageCode, CancellationToken cancellationToken)
|
||||
{
|
||||
var model = Configuration.Settings.Tools.LmStudioModel;
|
||||
var modelJson = string.Empty;
|
||||
if (!string.IsNullOrEmpty(model))
|
||||
{
|
||||
modelJson = "\"model\": \"" + model + "\",";
|
||||
Configuration.Settings.Tools.LmStudioModel = model;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(Configuration.Settings.Tools.LmStudioPrompt))
|
||||
{
|
||||
Configuration.Settings.Tools.LmStudioPrompt = "Translate from {0} to {1}, keep sentences in {1} as they are, do not censor the translation, give only the output without commenting on what you read:";
|
||||
}
|
||||
var prompt = string.Format(Configuration.Settings.Tools.LmStudioPrompt, sourceLanguageCode, targetLanguageCode);
|
||||
var input = "{ " + modelJson + " \"messages\": [{ \"role\": \"user\", \"content\": \"" + prompt + "\\n\\n" + Json.EncodeJsonText(text.Trim()) + "\" }]}";
|
||||
var content = new StringContent(input, Encoding.UTF8);
|
||||
content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
|
||||
var result = await _httpClient.PostAsync(string.Empty, content, cancellationToken);
|
||||
var bytes = await result.Content.ReadAsByteArrayAsync();
|
||||
var json = Encoding.UTF8.GetString(bytes).Trim();
|
||||
if (!result.IsSuccessStatusCode)
|
||||
{
|
||||
Error = json;
|
||||
SeLogger.Error("Error calling + " + StaticName + ": Status code=" + result.StatusCode + Environment.NewLine + json);
|
||||
}
|
||||
|
||||
result.EnsureSuccessStatusCode();
|
||||
|
||||
var parser = new SeJsonParser();
|
||||
var resultText = parser.GetFirstObject(json, "content");
|
||||
if (resultText == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var outputText = Json.DecodeJsonText(resultText).Trim();
|
||||
if (outputText.StartsWith('"') && outputText.EndsWith('"') && !text.StartsWith('"'))
|
||||
{
|
||||
outputText = outputText.Trim('"').Trim();
|
||||
}
|
||||
|
||||
return outputText;
|
||||
}
|
||||
}
|
||||
}
|
89
src/libse/AutoTranslate/OllamaTranslate.cs
Normal file
89
src/libse/AutoTranslate/OllamaTranslate.cs
Normal file
@ -0,0 +1,89 @@
|
||||
using Nikse.SubtitleEdit.Core.Common;
|
||||
using Nikse.SubtitleEdit.Core.SubtitleFormats;
|
||||
using Nikse.SubtitleEdit.Core.Translate;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.AutoTranslate
|
||||
{
|
||||
public class OllamaTranslate : IAutoTranslator
|
||||
{
|
||||
private HttpClient _httpClient;
|
||||
|
||||
public static string StaticName { get; set; } = "Ollama (local LLM)";
|
||||
public string Name => StaticName;
|
||||
public string Url => "https://github.com/ollama/ollama";
|
||||
public string Error { get; set; }
|
||||
public int MaxCharacters => 1000;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_httpClient?.Dispose();
|
||||
_httpClient = new HttpClient();
|
||||
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
|
||||
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation("accept", "application/json");
|
||||
_httpClient.BaseAddress = new Uri(Configuration.Settings.Tools.OllamaApiUrl.TrimEnd('/'));
|
||||
_httpClient.Timeout = TimeSpan.FromMinutes(25);
|
||||
}
|
||||
|
||||
public List<TranslationPair> GetSupportedSourceLanguages()
|
||||
{
|
||||
return ChatGptTranslate.ListLanguages();
|
||||
}
|
||||
|
||||
public List<TranslationPair> GetSupportedTargetLanguages()
|
||||
{
|
||||
return ChatGptTranslate.ListLanguages();
|
||||
}
|
||||
|
||||
public async Task<string> Translate(string text, string sourceLanguageCode, string targetLanguageCode, CancellationToken cancellationToken)
|
||||
{
|
||||
var model = Configuration.Settings.Tools.OllamaModel;
|
||||
var modelJson = string.Empty;
|
||||
if (!string.IsNullOrEmpty(model))
|
||||
{
|
||||
modelJson = "\"model\": \"" + model + "\",";
|
||||
Configuration.Settings.Tools.OllamaModel = model;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(Configuration.Settings.Tools.OllamaPrompt))
|
||||
{
|
||||
Configuration.Settings.Tools.OllamaPrompt = "Translate from {0} to {1}, keep sentences in {1} as they are, do not censor the translation, give only the output without commenting on what you read:";
|
||||
}
|
||||
var prompt = string.Format(Configuration.Settings.Tools.OllamaPrompt, sourceLanguageCode, targetLanguageCode);
|
||||
var input = "{ " + modelJson + " \"prompt\": \"" + prompt + "\\n\\n" + Json.EncodeJsonText(text.Trim()) + "\", \"stream\": false }";
|
||||
var content = new StringContent(input, Encoding.UTF8);
|
||||
content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
|
||||
var result = await _httpClient.PostAsync(string.Empty, content, cancellationToken);
|
||||
var bytes = await result.Content.ReadAsByteArrayAsync();
|
||||
var json = Encoding.UTF8.GetString(bytes).Trim();
|
||||
if (!result.IsSuccessStatusCode)
|
||||
{
|
||||
Error = json;
|
||||
SeLogger.Error("Error calling + " + StaticName + ": Status code=" + result.StatusCode + Environment.NewLine + json);
|
||||
}
|
||||
|
||||
result.EnsureSuccessStatusCode();
|
||||
|
||||
var parser = new SeJsonParser();
|
||||
var resultText = parser.GetFirstObject(json, "response");
|
||||
if (resultText == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var outputText = Json.DecodeJsonText(resultText).Trim();
|
||||
if (outputText.StartsWith('"') && outputText.EndsWith('"') && !text.StartsWith('"'))
|
||||
{
|
||||
outputText = outputText.Trim('"').Trim();
|
||||
}
|
||||
|
||||
return outputText;
|
||||
}
|
||||
}
|
||||
}
|
@ -177,6 +177,13 @@ namespace Nikse.SubtitleEdit.Core.Common
|
||||
public string ChatGptPrompt { get; set; }
|
||||
public string ChatGptApiKey { get; set; }
|
||||
public string ChatGptModel { get; set; }
|
||||
public string LmStudioApiUrl { get; set; }
|
||||
public string LmStudioModel { get; set; }
|
||||
public string LmStudioPrompt { get; set; }
|
||||
public string OllamaApiUrl { get; set; }
|
||||
public string OllamaModel { get; set; }
|
||||
public string OllamaPrompt { get; set; }
|
||||
|
||||
public string AnthropicApiUrl { get; set; }
|
||||
public string AnthropicPrompt { get; set; }
|
||||
public string AnthropicApiKey { get; set; }
|
||||
@ -539,6 +546,7 @@ namespace Nikse.SubtitleEdit.Core.Common
|
||||
ChatGptUrl = "https://api.openai.com/v1/chat/completions";
|
||||
ChatGptPrompt = "Translate from {0} to {1}, keep sentences in {1} as they are, do not censor the translation, give only the output without commenting on what you read:";
|
||||
ChatGptModel = "gpt-3.5-turbo";
|
||||
OllamaApiUrl = "http://localhost:11434/api/generate";
|
||||
AnthropicApiUrl = "https://api.anthropic.com/v1/messages";
|
||||
AnthropicPrompt = "Translate from {0} to {1}, keep sentences in {1} as they are, do not censor the translation, give only the output without commenting on what you read:";
|
||||
AnthropicApiModel = "claude-3-opus-20240229";
|
||||
@ -5367,6 +5375,42 @@ $HorzAlign = Center
|
||||
settings.Tools.ChatGptModel = subNode.InnerText;
|
||||
}
|
||||
|
||||
subNode = node.SelectSingleNode("LmStudioApiUrl");
|
||||
if (subNode != null)
|
||||
{
|
||||
settings.Tools.LmStudioApiUrl = subNode.InnerText;
|
||||
}
|
||||
|
||||
subNode = node.SelectSingleNode("LmStudioModel");
|
||||
if (subNode != null)
|
||||
{
|
||||
settings.Tools.LmStudioModel = subNode.InnerText;
|
||||
}
|
||||
|
||||
subNode = node.SelectSingleNode("LmStudioPrompt");
|
||||
if (subNode != null)
|
||||
{
|
||||
settings.Tools.LmStudioPrompt = subNode.InnerText;
|
||||
}
|
||||
|
||||
subNode = node.SelectSingleNode("OllamaApiUrl");
|
||||
if (subNode != null)
|
||||
{
|
||||
settings.Tools.OllamaApiUrl = subNode.InnerText;
|
||||
}
|
||||
|
||||
subNode = node.SelectSingleNode("OllamaModel");
|
||||
if (subNode != null)
|
||||
{
|
||||
settings.Tools.OllamaModel = subNode.InnerText;
|
||||
}
|
||||
|
||||
subNode = node.SelectSingleNode("OllamaPrompt");
|
||||
if (subNode != null)
|
||||
{
|
||||
settings.Tools.OllamaPrompt = subNode.InnerText;
|
||||
}
|
||||
|
||||
subNode = node.SelectSingleNode("AnthropicApiUrl");
|
||||
if (subNode != null)
|
||||
{
|
||||
@ -11905,7 +11949,13 @@ $HorzAlign = Center
|
||||
textWriter.WriteElementString("ChatGptPrompt", settings.Tools.ChatGptPrompt);
|
||||
textWriter.WriteElementString("ChatGptApiKey", settings.Tools.ChatGptApiKey);
|
||||
textWriter.WriteElementString("ChatGptModel", settings.Tools.ChatGptModel);
|
||||
textWriter.WriteElementString("AnthropicApiUrl", settings.Tools.AnthropicApiUrl);
|
||||
textWriter.WriteElementString("LmStudioApiUrl", settings.Tools.LmStudioApiUrl);
|
||||
textWriter.WriteElementString("LmStudioModel", settings.Tools.LmStudioModel);
|
||||
textWriter.WriteElementString("LmStudioPrompt", settings.Tools.LmStudioPrompt);
|
||||
textWriter.WriteElementString("LmStudioApiUrl", settings.Tools.LmStudioApiUrl);
|
||||
textWriter.WriteElementString("OllamaModel", settings.Tools.OllamaModel);
|
||||
textWriter.WriteElementString("OllamaPrompt", settings.Tools.OllamaPrompt);
|
||||
textWriter.WriteElementString("OllamaApiUrl", settings.Tools.OllamaApiUrl);
|
||||
textWriter.WriteElementString("AnthropicPrompt", settings.Tools.AnthropicPrompt);
|
||||
textWriter.WriteElementString("AnthropicApiKey", settings.Tools.AnthropicApiKey);
|
||||
textWriter.WriteElementString("AnthropicApiModel", settings.Tools.AnthropicApiModel);
|
||||
|
@ -123,6 +123,8 @@ namespace Nikse.SubtitleEdit.Forms.Translate
|
||||
new LibreTranslate(),
|
||||
new MyMemoryApi(),
|
||||
new ChatGptTranslate(),
|
||||
new LmStudioTranslate(),
|
||||
new OllamaTranslate(),
|
||||
new AnthropicTranslate(),
|
||||
new GeminiTranslate(),
|
||||
new PapagoTranslate(),
|
||||
@ -310,6 +312,59 @@ namespace Nikse.SubtitleEdit.Forms.Translate
|
||||
return;
|
||||
}
|
||||
|
||||
if (engineType == typeof(LmStudioTranslate))
|
||||
{
|
||||
if (string.IsNullOrEmpty(Configuration.Settings.Tools.LmStudioApiUrl))
|
||||
{
|
||||
Configuration.Settings.Tools.LmStudioApiUrl = "http://localhost:1234/v1/chat/completions";
|
||||
}
|
||||
|
||||
FillUrls(new List<string>
|
||||
{
|
||||
Configuration.Settings.Tools.LmStudioApiUrl.TrimEnd('/'),
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (engineType == typeof(OllamaTranslate))
|
||||
{
|
||||
if (Configuration.Settings.Tools.OllamaApiUrl == null)
|
||||
{
|
||||
Configuration.Settings.Tools.OllamaApiUrl = "http://localhost:11434/api/generate";
|
||||
}
|
||||
|
||||
FillUrls(new List<string>
|
||||
{
|
||||
Configuration.Settings.Tools.OllamaApiUrl.TrimEnd('/'),
|
||||
});
|
||||
|
||||
labelFormality.Text = LanguageSettings.Current.AudioToText.Model;
|
||||
labelFormality.Visible = true;
|
||||
comboBoxFormality.Left = labelFormality.Right + 3;
|
||||
comboBoxFormality.Visible = true;
|
||||
comboBoxFormality.DropDownStyle = ComboBoxStyle.DropDown;
|
||||
comboBoxFormality.Items.Clear();
|
||||
comboBoxFormality.Items.Add("llama2");
|
||||
comboBoxFormality.Items.Add("mistral");
|
||||
comboBoxFormality.Items.Add("dolphin-phi");
|
||||
comboBoxFormality.Items.Add("phi");
|
||||
comboBoxFormality.Items.Add("neural-chat");
|
||||
comboBoxFormality.Items.Add("starling-lm");
|
||||
comboBoxFormality.Items.Add("codellama");
|
||||
comboBoxFormality.Items.Add("llama2-uncensored");
|
||||
comboBoxFormality.Items.Add("llama2:13b");
|
||||
comboBoxFormality.Items.Add("llama2:70b");
|
||||
comboBoxFormality.Items.Add("orca-mini");
|
||||
comboBoxFormality.Items.Add("vicuna");
|
||||
comboBoxFormality.Items.Add("llava");
|
||||
comboBoxFormality.Items.Add("gemma:2b");
|
||||
comboBoxFormality.Items.Add("gemma:7b");
|
||||
comboBoxFormality.Text = Configuration.Settings.Tools.OllamaModel;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (engineType == typeof(AnthropicTranslate))
|
||||
{
|
||||
FillUrls(new List<string>
|
||||
@ -323,6 +378,7 @@ namespace Nikse.SubtitleEdit.Forms.Translate
|
||||
labelApiKey.Visible = true;
|
||||
nikseTextBoxApiKey.Visible = true;
|
||||
|
||||
labelFormality.Text = LanguageSettings.Current.AudioToText.Model;
|
||||
labelFormality.Visible = true;
|
||||
comboBoxFormality.Left = labelFormality.Right + 3;
|
||||
comboBoxFormality.Visible = true;
|
||||
@ -331,8 +387,6 @@ namespace Nikse.SubtitleEdit.Forms.Translate
|
||||
comboBoxFormality.Items.Add("claude-3-opus-20240229");
|
||||
comboBoxFormality.Items.Add("claude-3-sonnet-20240229");
|
||||
comboBoxFormality.Items.Add("claude-3-haiku-20240307");
|
||||
comboBoxFormality.Text = Configuration.Settings.Tools.AnthropicApiModel;
|
||||
labelFormality.Text = LanguageSettings.Current.AudioToText.Model;
|
||||
|
||||
return;
|
||||
}
|
||||
@ -887,7 +941,11 @@ namespace Nikse.SubtitleEdit.Forms.Translate
|
||||
nikseComboBoxUrl.Text.Contains("//127.", StringComparison.OrdinalIgnoreCase) ||
|
||||
nikseComboBoxUrl.Text.Contains("//localhost", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
if (engineType == typeof(NoLanguageLeftBehindApi) || engineType == typeof(NoLanguageLeftBehindServe) || engineType == typeof(LibreTranslate))
|
||||
if (engineType == typeof(NoLanguageLeftBehindApi) ||
|
||||
engineType == typeof(NoLanguageLeftBehindServe) ||
|
||||
engineType == typeof(LibreTranslate) ||
|
||||
engineType == typeof(LmStudioTranslate) ||
|
||||
engineType == typeof(OllamaTranslate))
|
||||
{
|
||||
var dr = MessageBox.Show(
|
||||
string.Format(LanguageSettings.Current.GoogleTranslate.XRequiresALocalWebServer, _autoTranslator.Name)
|
||||
@ -944,6 +1002,18 @@ namespace Nikse.SubtitleEdit.Forms.Translate
|
||||
Configuration.Settings.Tools.ChatGptUrl = nikseComboBoxUrl.Text.Trim();
|
||||
}
|
||||
|
||||
if (engineType == typeof(LmStudioTranslate))
|
||||
{
|
||||
Configuration.Settings.Tools.LmStudioApiUrl = nikseComboBoxUrl.Text.Trim();
|
||||
Configuration.Settings.Tools.LmStudioModel = comboBoxFormality.Text.Trim();
|
||||
}
|
||||
|
||||
if (engineType == typeof(OllamaTranslate))
|
||||
{
|
||||
Configuration.Settings.Tools.OllamaApiUrl = nikseComboBoxUrl.Text.Trim();
|
||||
Configuration.Settings.Tools.OllamaModel = comboBoxFormality.Text.Trim();
|
||||
}
|
||||
|
||||
if (engineType == typeof(AnthropicTranslate) && !string.IsNullOrWhiteSpace(nikseTextBoxApiKey.Text))
|
||||
{
|
||||
Configuration.Settings.Tools.AnthropicApiKey = nikseTextBoxApiKey.Text.Trim();
|
||||
|
Loading…
Reference in New Issue
Block a user