From 1f71879e0f1d1b7cef23c91a8e57e1868c98fbe4 Mon Sep 17 00:00:00 2001
From: lq1405 <2769838458@qq.com>
Date: Fri, 25 Jul 2025 12:47:29 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=8F=90=E7=A4=BA=E8=AF=8D?=
=?UTF-8?q?=E7=BF=BB=E8=AF=91=20=E6=89=80=E6=9C=89=E7=9A=84=E6=8F=90?=
=?UTF-8?q?=E7=A4=BA=E8=AF=8D=20=E4=B8=AD=E6=96=87=E7=BF=BB=E8=AF=91?=
=?UTF-8?q?=E4=B8=BA=E8=8B=B1=E6=96=87=EF=BC=81=EF=BC=81=EF=BC=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 4 +-
.../Extensions/HttpContextExtensions.cs | 45 ++++
...teHandlerBuilderAuthorizationExtensions.cs | 2 -
.../Filters/SplitMJAuthorizationFilter.cs | 2 -
src/Common/Helper/ConfigHelper.cs | 104 +++++++-
src/Common/Helper/JSONHelper.cs | 239 ++++++++++++++++++
src/Common/Helper/ServiceLocator.cs | 83 ++++++
src/Configuration/config/transfer-temp.json | 19 ++
src/Configuration/config/transfer.json | 6 -
src/ConfigureServices.cs | 25 ++
.../MJTransferEndpoint/MJGetFetchIdService.cs | 6 +-
.../MJPostImagineService.cs | 95 ++++++-
.../MJTransferEndpoint/MJPostModalService.cs | 11 +
.../MJPostUploadDiscordImages.cs | 1 -
src/Examples/ServiceUsageExamples.cs | 88 +++++++
src/Program.cs | 3 +
src/Services/BaiduTranslateService.cs | 104 ++++++++
src/Services/GPTTranslateService.cs | 105 ++++++++
src/Services/ITranslateService.cs | 9 +
src/Tool/Extensions/JsonConfigReader.cs | 7 +
20 files changed, 926 insertions(+), 32 deletions(-)
create mode 100644 src/Common/Helper/ServiceLocator.cs
create mode 100644 src/Configuration/config/transfer-temp.json
delete mode 100644 src/Configuration/config/transfer.json
create mode 100644 src/Examples/ServiceUsageExamples.cs
create mode 100644 src/Services/BaiduTranslateService.cs
create mode 100644 src/Services/GPTTranslateService.cs
create mode 100644 src/Services/ITranslateService.cs
diff --git a/.gitignore b/.gitignore
index 9491a2f..223ece1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -360,4 +360,6 @@ MigrationBackup/
.ionide/
# Fody - auto-generated XML schema
-FodyWeavers.xsd
\ No newline at end of file
+FodyWeavers.xsd
+/src/Configuration/config/transfer.json
+/src/Configuration/config/transfer.json
diff --git a/src/Common/Extensions/HttpContextExtensions.cs b/src/Common/Extensions/HttpContextExtensions.cs
index d22f83f..45e8d88 100644
--- a/src/Common/Extensions/HttpContextExtensions.cs
+++ b/src/Common/Extensions/HttpContextExtensions.cs
@@ -55,5 +55,50 @@ namespace lai_transfer.Common.Extensions
return fullPath;
}
+ ///
+ /// 从HttpContext的RequestServices中获取服务
+ ///
+ /// 服务类型
+ /// Http上下文
+ /// 服务实例,如果未找到则返回null
+ public static T? GetService(this HttpContext httpContext) where T : class
+ {
+ return httpContext.RequestServices.GetService();
+ }
+
+ ///
+ /// 从HttpContext的RequestServices中获取必需的服务
+ ///
+ /// 服务类型
+ /// Http上下文
+ /// 服务实例
+ /// 如果服务未注册则抛出异常
+ public static T GetRequiredService(this HttpContext httpContext) where T : notnull
+ {
+ return httpContext.RequestServices.GetRequiredService();
+ }
+
+ ///
+ /// 从HttpContext的RequestServices中获取服务(非泛型版本)
+ ///
+ /// Http上下文
+ /// 服务类型
+ /// 服务实例,如果未找到则返回null
+ public static object? GetService(this HttpContext httpContext, Type serviceType)
+ {
+ return httpContext.RequestServices.GetService(serviceType);
+ }
+
+ ///
+ /// 从HttpContext的RequestServices中获取必需的服务(非泛型版本)
+ ///
+ /// Http上下文
+ /// 服务类型
+ /// 服务实例
+ /// 如果服务未注册则抛出异常
+ public static object GetRequiredService(this HttpContext httpContext, Type serviceType)
+ {
+ return httpContext.RequestServices.GetRequiredService(serviceType);
+ }
}
}
diff --git a/src/Common/Extensions/RouteHandlerBuilderAuthorizationExtensions.cs b/src/Common/Extensions/RouteHandlerBuilderAuthorizationExtensions.cs
index 465bcfd..4882d92 100644
--- a/src/Common/Extensions/RouteHandlerBuilderAuthorizationExtensions.cs
+++ b/src/Common/Extensions/RouteHandlerBuilderAuthorizationExtensions.cs
@@ -1,6 +1,4 @@
using lai_transfer.Common.Filters;
-using lai_transfer.Configuration;
-using Microsoft.AspNetCore.Mvc.Filters;
namespace lai_transfer.Common.Extensions
{
diff --git a/src/Common/Filters/SplitMJAuthorizationFilter.cs b/src/Common/Filters/SplitMJAuthorizationFilter.cs
index ceef808..f7464c1 100644
--- a/src/Common/Filters/SplitMJAuthorizationFilter.cs
+++ b/src/Common/Filters/SplitMJAuthorizationFilter.cs
@@ -62,8 +62,6 @@
return TypedResults.Unauthorized();
}
}
-
-
}
}
}
\ No newline at end of file
diff --git a/src/Common/Helper/ConfigHelper.cs b/src/Common/Helper/ConfigHelper.cs
index 936d316..392a5a1 100644
--- a/src/Common/Helper/ConfigHelper.cs
+++ b/src/Common/Helper/ConfigHelper.cs
@@ -6,14 +6,6 @@ namespace lai_transfer.Common.Helper
{
private static readonly ILogger _logger = LogHelper.GetLogger();
- // 存储Origin配置
- public static class Origin
- {
- // 将private set改为internal set,允许同一程序集中的代码设置属性值
- public static string BaseUrl { get; internal set; }
- public static string Token { get; internal set; }
- }
-
// 初始化配置
public static void Initialize()
{
@@ -24,15 +16,105 @@ namespace lai_transfer.Common.Helper
// 读取配置文件
var reader = new JsonConfigReader("Configuration/config/transfer.json");
- // 加载Origin配置
- Origin.BaseUrl = reader.GetString("Origin.BaseUrl") ?? string.Empty;
- Origin.Token = reader.GetString("Origin.Token") ?? string.Empty;
+ // 初始化Origin配置
+ Origin.Init(reader);
+
+ Translate.Init(reader);
_logger.LogInformation("配置加载完成");
}
catch (Exception ex)
{
_logger.LogError(ex, "加载配置文件失败");
+ // 报错,结束程序运行
+ throw new InvalidOperationException("无法加载应用程序配置,请检查配置文件是否存在或格式是否正确。", ex);
+ }
+ }
+
+ public static class Translate
+ {
+ // 将private set改为internal set,允许同一程序集中的代码设置属性值
+ public static bool Enable { get; internal set; } = false;
+
+ // 安全模式 会优先百度 百度 报错 再使用OpenAI
+ public static string Model { get; internal set; } = "BAIDU";
+
+ public static string BaiduAppId { get; internal set; } = string.Empty;
+ public static string BaiduAppSecret { get; internal set; } = string.Empty;
+ public static string OpenaiGptApiUrl { get; internal set; } = string.Empty;
+ public static string OpenaiGptApiKey { get; internal set; } = string.Empty;
+ public static TimeSpan TimeOut { get; internal set; } = TimeSpan.FromSeconds(10);
+
+ public static string OpenaiGptModel { get; internal set; } = "gpt-4o-mini";
+
+ public static int OpenaiGptMaxTokens { get; internal set; } = 2048;
+
+ public static double OpenaiGptTemperature { get; internal set; } = 0;
+
+
+ ///
+ /// 初始化翻译配置
+ ///
+
+ public static void Init(JsonConfigReader reader)
+ {
+ try
+ {
+ _logger.LogInformation("正在加载翻译配置...");
+ // 加载翻译配置
+ Enable = reader.GetBool("Translate.Enable") ?? false;
+ Model = reader.GetString("Translate.Model") ?? "BAIDU";
+ BaiduAppId = reader.GetString("Translate.BaiduAppId") ?? string.Empty;
+ BaiduAppSecret = reader.GetString("Translate.BaiduAppSecret") ?? string.Empty;
+
+ OpenaiGptApiUrl = reader.GetString("Translate.OpenaiGptApiUrl") ?? "https://laitooo.net";
+ OpenaiGptApiKey = reader.GetString("Translate.OpenaiGptApiKey") ?? string.Empty;
+ OpenaiGptModel = reader.GetString("Translate.OpenaiGptModel") ?? "Doubao-lite-32k";
+
+ OpenaiGptMaxTokens = reader.GetInt("Translate.OpenaiGptMaxTokens") ?? 2048;
+ OpenaiGptTemperature = reader.GetDouble("Translate.OpenaiGptTemperature") ?? 0;
+
+ TimeOut = TimeSpan.FromSeconds(reader.GetInt("Translate.TimeOut") ?? 20);
+ _logger.LogInformation("翻译配置加载完成");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "加载翻译配置失败");
+ // 报错,结束程序运行
+ throw new InvalidOperationException("无法加载翻译配置,请检查配置文件是否存在或格式是否正确。", ex);
+ }
+ }
+
+ }
+
+ // 存储Origin配置
+ public static class Origin
+ {
+ // 将private set改为internal set,允许同一程序集中的代码设置属性值
+ public static string BaseUrl { get; internal set; } = string.Empty;
+ public static string Token { get; internal set; } = string.Empty;
+
+ ///
+ /// 初始化Origin配置
+ ///
+ public static void Init(JsonConfigReader reader)
+ {
+ try
+ {
+
+ _logger.LogInformation("正在加载Origin配置...");
+ // 加载Origin配置
+ BaseUrl = reader.GetString("Origin.BaseUrl") ?? string.Empty;
+ Token = reader.GetString("Origin.Token") ?? string.Empty;
+
+ _logger.LogInformation("Origin配置加载完成");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "加载Origin配置失败");
+ // 报错,结束程序运行
+ throw new InvalidOperationException("无法加载Origin配置,请检查配置文件是否存在或格式是否正确。", ex);
+ }
}
}
}
diff --git a/src/Common/Helper/JSONHelper.cs b/src/Common/Helper/JSONHelper.cs
index 7a24dbf..cfc08c5 100644
--- a/src/Common/Helper/JSONHelper.cs
+++ b/src/Common/Helper/JSONHelper.cs
@@ -34,5 +34,244 @@ namespace lai_transfer.Common.Helper
return Encoding.UTF8.GetString(stream.ToArray());
}
+
+ ///
+ /// 获取指定属性的值
+ ///
+ /// JSON元素
+ /// 属性名称
+ /// 属性值的JsonElement,如果属性不存在则返回null
+ public static JsonElement? GetJsonProperty(JsonElement element, string propertyName)
+ {
+ // 检查元素是否为对象
+ if (element.ValueKind != JsonValueKind.Object)
+ return null;
+
+ // 尝试获取属性
+ if (element.TryGetProperty(propertyName, out JsonElement property))
+ {
+ return property;
+ }
+
+ return null;
+ }
+
+ ///
+ /// 获取指定属性的字符串值
+ ///
+ /// JSON元素
+ /// 属性名称
+ /// 属性的字符串值,如果属性不存在或无法转换则返回null
+ public static string? GetJsonPropertyString(JsonElement element, string propertyName)
+ {
+ var property = GetJsonProperty(element, propertyName);
+ return property?.GetString();
+ }
+
+ ///
+ /// 获取指定属性的整数值
+ ///
+ /// JSON元素
+ /// 属性名称
+ /// 属性的整数值,如果属性不存在或无法转换则返回null
+ public static int? GetJsonPropertyInt(JsonElement element, string propertyName)
+ {
+ var property = GetJsonProperty(element, propertyName);
+ if (property.HasValue && property.Value.TryGetInt32(out int value))
+ {
+ return value;
+ }
+ return null;
+ }
+
+ ///
+ /// 获取指定属性的布尔值
+ ///
+ /// JSON元素
+ /// 属性名称
+ /// 属性的布尔值,如果属性不存在或无法转换则返回null
+ public static bool? GetJsonPropertyBool(JsonElement element, string propertyName)
+ {
+ var property = GetJsonProperty(element, propertyName);
+ if (property.HasValue)
+ {
+ try
+ {
+ return property.Value.GetBoolean();
+ }
+ catch
+ {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// 设置或更新JSON对象中指定属性的值
+ ///
+ /// JSON元素
+ /// 属性名称
+ /// 要设置的值
+ /// 更新后的JsonElement
+ public static JsonElement SetJsonProperty(JsonElement element, string propertyName, object? value)
+ {
+ // 检查元素是否为对象
+ if (element.ValueKind != JsonValueKind.Object)
+ return element;
+
+ using var stream = new MemoryStream();
+ using var writer = new Utf8JsonWriter(stream);
+
+ writer.WriteStartObject();
+
+ bool propertyFound = false;
+
+ // 遍历所有现有属性
+ foreach (var property in element.EnumerateObject())
+ {
+ if (property.Name == propertyName)
+ {
+ // 写入新值
+ WritePropertyValue(writer, propertyName, value);
+ propertyFound = true;
+ }
+ else
+ {
+ // 保留现有属性
+ property.WriteTo(writer);
+ }
+ }
+
+ // 如果属性不存在,添加新属性
+ if (!propertyFound)
+ {
+ WritePropertyValue(writer, propertyName, value);
+ }
+
+ writer.WriteEndObject();
+ writer.Flush();
+
+ // 解析生成的JSON并返回JsonElement
+ var jsonString = Encoding.UTF8.GetString(stream.ToArray());
+ using var document = JsonDocument.Parse(jsonString);
+ return document.RootElement.Clone();
+ }
+
+ ///
+ /// 设置或更新JSON对象中指定属性的值,返回JSON字符串
+ ///
+ /// JSON元素
+ /// 属性名称
+ /// 要设置的值
+ /// 更新后的JSON字符串
+ public static string SetJsonPropertyAsString(JsonElement element, string propertyName, object? value)
+ {
+ var updatedElement = SetJsonProperty(element, propertyName, value);
+ return updatedElement.GetRawText();
+ }
+
+ ///
+ /// 设置多个属性的值
+ ///
+ /// JSON元素
+ /// 属性名称和值的字典
+ /// 更新后的JSON字符串
+ public static string SetJsonProperties(JsonElement element, Dictionary properties)
+ {
+ // 检查元素是否为对象
+ if (element.ValueKind != JsonValueKind.Object)
+ return element.GetRawText();
+
+ using var stream = new MemoryStream();
+ using var writer = new Utf8JsonWriter(stream);
+
+ writer.WriteStartObject();
+
+ var processedProperties = new HashSet();
+
+ // 遍历所有现有属性
+ foreach (var property in element.EnumerateObject())
+ {
+ if (properties.ContainsKey(property.Name))
+ {
+ // 写入新值
+ WritePropertyValue(writer, property.Name, properties[property.Name]);
+ processedProperties.Add(property.Name);
+ }
+ else
+ {
+ // 保留现有属性
+ property.WriteTo(writer);
+ }
+ }
+
+ // 添加不存在的新属性
+ foreach (var kvp in properties)
+ {
+ if (!processedProperties.Contains(kvp.Key))
+ {
+ WritePropertyValue(writer, kvp.Key, kvp.Value);
+ }
+ }
+
+ writer.WriteEndObject();
+ writer.Flush();
+
+ return Encoding.UTF8.GetString(stream.ToArray());
+ }
+
+ ///
+ /// 写入属性值到JSON writer
+ ///
+ /// JSON writer
+ /// 属性名称
+ /// 属性值
+ private static void WritePropertyValue(Utf8JsonWriter writer, string propertyName, object? value)
+ {
+ writer.WritePropertyName(propertyName);
+
+ switch (value)
+ {
+ case null:
+ writer.WriteNullValue();
+ break;
+ case string stringValue:
+ writer.WriteStringValue(stringValue);
+ break;
+ case int intValue:
+ writer.WriteNumberValue(intValue);
+ break;
+ case long longValue:
+ writer.WriteNumberValue(longValue);
+ break;
+ case float floatValue:
+ writer.WriteNumberValue(floatValue);
+ break;
+ case double doubleValue:
+ writer.WriteNumberValue(doubleValue);
+ break;
+ case decimal decimalValue:
+ writer.WriteNumberValue(decimalValue);
+ break;
+ case bool boolValue:
+ writer.WriteBooleanValue(boolValue);
+ break;
+ case DateTime dateTimeValue:
+ writer.WriteStringValue(dateTimeValue.ToString("O")); // ISO 8601 format
+ break;
+ case JsonElement jsonElement:
+ jsonElement.WriteTo(writer);
+ break;
+ default:
+ {
+ // 对于复杂对象,序列化为JSON字符串
+ var jsonString = JsonSerializer.Serialize(value);
+ using var doc = JsonDocument.Parse(jsonString);
+ doc.RootElement.WriteTo(writer);
+ break;
+ }
+ }
+ }
}
}
diff --git a/src/Common/Helper/ServiceLocator.cs b/src/Common/Helper/ServiceLocator.cs
new file mode 100644
index 0000000..794acbf
--- /dev/null
+++ b/src/Common/Helper/ServiceLocator.cs
@@ -0,0 +1,83 @@
+namespace lai_transfer.Common.Helper
+{
+ ///
+ /// ȫַλûHttpContextĵطȡעķ
+ ///
+ public static class ServiceLocator
+ {
+ private static IServiceProvider? _serviceProvider;
+
+ ///
+ /// ʼṩߣProgram.csеã
+ ///
+ /// ṩ
+ public static void Initialize(IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ }
+
+ ///
+ /// ȡ
+ ///
+ ///
+ /// ʵδҵnull
+ public static T? GetService() where T : class
+ {
+ EnsureInitialized();
+ return _serviceProvider!.GetService();
+ }
+
+ ///
+ /// ȡķ
+ ///
+ ///
+ /// ʵ
+ /// δע׳쳣
+ public static T GetRequiredService() where T : notnull
+ {
+ EnsureInitialized();
+ return _serviceProvider!.GetRequiredService();
+ }
+
+ ///
+ /// ȡǷͰ汾
+ ///
+ ///
+ /// ʵδҵnull
+ public static object? GetService(Type serviceType)
+ {
+ EnsureInitialized();
+ return _serviceProvider!.GetService(serviceType);
+ }
+
+ ///
+ /// ȡķǷͰ汾
+ ///
+ ///
+ /// ʵ
+ /// δע׳쳣
+ public static object GetRequiredService(Type serviceType)
+ {
+ EnsureInitialized();
+ return _serviceProvider!.GetRequiredService(serviceType);
+ }
+
+ ///
+ /// Χ
+ ///
+ /// Χ
+ public static IServiceScope CreateScope()
+ {
+ EnsureInitialized();
+ return _serviceProvider!.CreateScope();
+ }
+
+ private static void EnsureInitialized()
+ {
+ if (_serviceProvider == null)
+ {
+ throw new InvalidOperationException("ServiceLocator δʼ Program.cs е ServiceLocator.Initialize(app.Services)");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Configuration/config/transfer-temp.json b/src/Configuration/config/transfer-temp.json
new file mode 100644
index 0000000..a1fb908
--- /dev/null
+++ b/src/Configuration/config/transfer-temp.json
@@ -0,0 +1,19 @@
+{
+ "Origin": {
+ "BaseUrl": "https://mjapi.bzu.cn",
+ "Token": "23830faf80e8e69"
+ },
+ "Translate": {
+ "Enable": true,
+ "Model": "BAIDU",
+ "BaiduAppId": "2024032500",
+ "BaiduAppSecret": "hcCG8H",
+ "OpenaiGptApiUrl": "https://laitool.net/v1/chat/completions",
+
+ "OpenaiGptApiKey": "sk-r5",
+ "OpenaiGptModel": "Doubao-pro-32k",
+ "OpenaiGptMaxTokens": 2048,
+ "OpenaiGptTemperature": 0,
+ "TimeOut": 20
+ }
+}
diff --git a/src/Configuration/config/transfer.json b/src/Configuration/config/transfer.json
deleted file mode 100644
index aa83fe3..0000000
--- a/src/Configuration/config/transfer.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "Origin": {
- "BaseUrl": "https://mjapi.bzu.cn",
- "Token": "23830faf80e8e69988b3fcd9aa08e9ad123"
- }
-}
diff --git a/src/ConfigureServices.cs b/src/ConfigureServices.cs
index d8bc178..35cade1 100644
--- a/src/ConfigureServices.cs
+++ b/src/ConfigureServices.cs
@@ -1,12 +1,17 @@
using FluentValidation;
using lai_transfer.Configuration;
using lai_transfer.Model.Entity;
+using lai_transfer.Services;
+using lai_transfer.EndpointServices.MJTransferEndpoint;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Serilog;
using System.Text;
+using Midjourney.Infrastructure.Services;
+using lai_transfer.Common.Helper;
namespace lai_transfer
{
@@ -40,11 +45,31 @@ namespace lai_transfer
// 添加JWT认证配置
builder.Services.AddJWTAuthentication();
+ builder.Services.AddService();
+
// 注册校验
builder.Services.AddValidatorsFromAssembly(typeof(ConfigureServices).Assembly);
}
+ ///
+ /// 注册一些服务
+ ///
+ ///
+ private static void AddService(this IServiceCollection services)
+ {
+ if (ConfigHelper.Translate.Model == "GPT")
+ {
+ // 翻译服务注入
+ services.AddSingleton();
+ }
+ else
+ {
+ services.AddSingleton();
+ }
+
+ }
+
///
/// JWT 配置
///
diff --git a/src/EndpointServices/MJTransferEndpoint/MJGetFetchIdService.cs b/src/EndpointServices/MJTransferEndpoint/MJGetFetchIdService.cs
index ad320c5..e745a43 100644
--- a/src/EndpointServices/MJTransferEndpoint/MJGetFetchIdService.cs
+++ b/src/EndpointServices/MJTransferEndpoint/MJGetFetchIdService.cs
@@ -220,7 +220,7 @@ namespace lai_transfer.EndpointServices.MJTransferEndpoint
if (isPartner && !string.IsNullOrEmpty(partnerTaskId))
{
- _logger.LogInformation($"处理合作伙伴任务: {partnerTaskId}");
+ _logger.LogInformation($"处理合作伙伴任务: {partnerTaskId}, TaskId : {data?.id ?? string.Empty}");
// 1111111111
@@ -279,7 +279,7 @@ namespace lai_transfer.EndpointServices.MJTransferEndpoint
if (isOfficial && !string.IsNullOrEmpty(officialTaskId))
{
- _logger.LogInformation($"处理官方任务: {officialTaskId}");
+ _logger.LogInformation($"处理官方任务: {officialTaskId}, TaskId : {data?.id ?? string.Empty}");
// 直接遍历,让异常处理兜底
var imageUrls = new List