From 8e533791765bec91413d3966dc7027b9b22b7c3a Mon Sep 17 00:00:00 2001 From: lq1405 <2769838458@qq.com> Date: Thu, 23 Oct 2025 18:12:06 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9mj=E8=BD=AC=E5=8F=91=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=9B=BE=E7=89=87=E5=90=88=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Extensions/HttpContextExtensions.cs | 8 +- .../Filters/SplitMJAuthorizationFilter.cs | 75 ++-- src/Common/Helper/ConfigHelper.cs | 39 ++ src/Common/Helper/QueryStringHelper.cs | 132 +++++++ src/Common/Helper/RetryHelper.cs | 199 +++++++++++ .../Results/TransferAuthorizationResult.cs | 22 +- src/Common/Types/MJType.cs | 16 + src/Configuration/DataBase/db.realm | Bin 0 -> 131072 bytes src/Configuration/DataBase/db.realm.lock | Bin 0 -> 1416 bytes src/Configuration/config/transfer-temp.json | 8 + src/ConfigureServices.cs | 26 +- .../MJTransferEndpoint/MJGetFetchIdService.cs | 15 +- .../MJGetImageSeedService.cs | 25 +- .../MJTransferEndpoint/MJPostActionService.cs | 24 +- .../MJTransferEndpoint/MJPostBlendService.cs | 25 +- .../MJPostDescribeService.cs | 25 +- .../MJPostFetchListByConditionService.cs | 134 +------ .../MJPostImagineService.cs | 108 +----- .../MJTransferEndpoint/MJPostModalService.cs | 32 +- .../MJPostShortenService.cs | 24 +- .../MJPostSwapFaceService.cs | 24 +- src/Examples/ServiceUsageExamples.cs | 88 ----- src/FodyWeavers.xml | 3 + src/Model/Entity/MJTask.cs | 59 ++++ src/Model/Midjourney/MidjourneyRequest.cs | 10 + .../Midjourney/MidjourneyTaskResponse.cs | 158 +++++++++ src/Program.cs | 8 +- src/Services/Midjourney/IMidjourneyService.cs | 43 +++ src/Services/Midjourney/MidjourneyService.cs | 332 ++++++++++++++++++ .../PeriodicTimedService .cs | 105 ++++++ .../RealmService/MJTaskRealmService.cs | 192 ++++++++++ src/Services/RealmService/RealmService.cs | 205 +++++++++++ .../{ => Translate}/BaiduTranslateService.cs | 6 +- .../{ => Translate}/GPTTranslateService.cs | 3 +- .../{ => Translate}/ITranslateService.cs | 2 +- src/Services/Translate/TranslateService.cs | 80 +++++ src/Tool/HttpTool/HttpService.cs | 302 ++++++++++++++++ src/Tool/HttpTool/IHttpService.cs | 50 +++ src/Tool/ImageTool/IImageService.cs | 14 + src/Tool/ImageTool/ImageService.cs | 118 +++++++ src/Tool/QiniuService/IQiniuService.cs | 57 +++ src/Tool/QiniuService/QiniuDataModel.cs | 33 ++ src/Tool/QiniuService/QiniuService.cs | 145 ++++++++ src/lai_transfer.csproj | 6 + 44 files changed, 2536 insertions(+), 444 deletions(-) create mode 100644 src/Common/Helper/QueryStringHelper.cs create mode 100644 src/Common/Helper/RetryHelper.cs create mode 100644 src/Common/Types/MJType.cs create mode 100644 src/Configuration/DataBase/db.realm create mode 100644 src/Configuration/DataBase/db.realm.lock delete mode 100644 src/Examples/ServiceUsageExamples.cs create mode 100644 src/FodyWeavers.xml create mode 100644 src/Model/Entity/MJTask.cs create mode 100644 src/Model/Midjourney/MidjourneyRequest.cs create mode 100644 src/Model/Midjourney/MidjourneyTaskResponse.cs create mode 100644 src/Services/Midjourney/IMidjourneyService.cs create mode 100644 src/Services/Midjourney/MidjourneyService.cs create mode 100644 src/Services/PeriodicTimeService/PeriodicTimedService .cs create mode 100644 src/Services/RealmService/MJTaskRealmService.cs create mode 100644 src/Services/RealmService/RealmService.cs rename src/Services/{ => Translate}/BaiduTranslateService.cs (97%) rename src/Services/{ => Translate}/GPTTranslateService.cs (98%) rename src/Services/{ => Translate}/ITranslateService.cs (77%) create mode 100644 src/Services/Translate/TranslateService.cs create mode 100644 src/Tool/HttpTool/HttpService.cs create mode 100644 src/Tool/HttpTool/IHttpService.cs create mode 100644 src/Tool/ImageTool/IImageService.cs create mode 100644 src/Tool/ImageTool/ImageService.cs create mode 100644 src/Tool/QiniuService/IQiniuService.cs create mode 100644 src/Tool/QiniuService/QiniuDataModel.cs create mode 100644 src/Tool/QiniuService/QiniuService.cs diff --git a/src/Common/Extensions/HttpContextExtensions.cs b/src/Common/Extensions/HttpContextExtensions.cs index 45e8d88..74654f4 100644 --- a/src/Common/Extensions/HttpContextExtensions.cs +++ b/src/Common/Extensions/HttpContextExtensions.cs @@ -27,11 +27,17 @@ namespace lai_transfer.Common.Extensions { string? token = httpContext.GetContextItem("AuthToken"); string? baseUrl = httpContext.GetContextItem("BaseUrl"); + if (!String.IsNullOrWhiteSpace(baseUrl) && baseUrl.EndsWith('/')) + { + baseUrl = baseUrl.TrimEnd('/'); + } + bool storage = Convert.ToBoolean(httpContext.GetContextItem("Storage") ?? "false"); + bool splice = Convert.ToBoolean(httpContext.GetContextItem("Splice") ?? "false"); if (string.IsNullOrWhiteSpace(token) || string.IsNullOrWhiteSpace(baseUrl)) { throw new InvalidOperationException("Authentication token or base URL is not set in the context."); } - return new TransferAuthorizationResult(token, baseUrl); + return new TransferAuthorizationResult(token, baseUrl, storage, splice, ""); } /// diff --git a/src/Common/Filters/SplitMJAuthorizationFilter.cs b/src/Common/Filters/SplitMJAuthorizationFilter.cs index f7464c1..e1269d9 100644 --- a/src/Common/Filters/SplitMJAuthorizationFilter.cs +++ b/src/Common/Filters/SplitMJAuthorizationFilter.cs @@ -1,4 +1,7 @@ -namespace lai_transfer.Common.Filters +using lai_transfer.Common.Helper; +using Newtonsoft.Json.Linq; + +namespace lai_transfer.Common.Filters { public class SplitMJAuthorizationFilter(ILogger logger) : IEndpointFilter { @@ -25,43 +28,43 @@ _logger.LogWarning("Authorization header is missing"); return TypedResults.Unauthorized(); } - else + + // 2. 处理令牌,判断是不是有前缀 删除前缀 + if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) { - // 2. 处理令牌,判断是不是有前缀 删除前缀 - if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) - { - authorization = authorization["Bearer ".Length..]; - } - if (authorization.Contains("?url=")) - { - // 使用Split方法拆分字符串 - string[] parts = authorization.Split("?url=", 2); - if (parts.Length == 2) - { - string token = parts[0].Trim(); - string baseUrl = parts[1].TrimEnd('/'); - if (string.IsNullOrWhiteSpace(authorization) || string.IsNullOrWhiteSpace(baseUrl)) - { - _logger.LogWarning("令牌或URL为空"); - return TypedResults.Unauthorized(); - } - httpContext.Items["AuthToken"] = token; - // 将baseUrl也存入HttpContext以便后续使用 - httpContext.Items["BaseUrl"] = baseUrl; - return await next(context); - } - else - { - _logger.LogWarning("令牌解析错误"); - return TypedResults.Unauthorized(); - } - } - else - { - _logger.LogWarning("令牌解析错误,没有包含 url"); - return TypedResults.Unauthorized(); - } + authorization = authorization["Bearer ".Length..]; } + + var result1 = QueryStringHelper.Parse(authorization); + + string token = result1.Prefix; + string baseUrl = result1.GetString("url"); + // 是否存储 + bool storage = result1.GetBool("storage", false); + + // 是否拼接 + bool splice = result1.GetBool("splice", false); + + // token 不能为空 + if (String.IsNullOrWhiteSpace(token)) + { + _logger.LogWarning("Authorization Invalid"); + return TypedResults.Unauthorized(); + } + + if (String.IsNullOrWhiteSpace(baseUrl)) + { + _logger.LogWarning("BaseUrl Invalid"); + return TypedResults.BadRequest("BaseUrl Invalid"); + } + + httpContext.Items["AuthToken"] = token; + // 将baseUrl也存入HttpContext以便后续使用 + httpContext.Items["BaseUrl"] = baseUrl; + httpContext.Items["Storage"] = storage; + httpContext.Items["Splice"] = splice; + return await next(context); + } } } \ No newline at end of file diff --git a/src/Common/Helper/ConfigHelper.cs b/src/Common/Helper/ConfigHelper.cs index 392a5a1..5a1e600 100644 --- a/src/Common/Helper/ConfigHelper.cs +++ b/src/Common/Helper/ConfigHelper.cs @@ -21,6 +21,8 @@ namespace lai_transfer.Common.Helper Translate.Init(reader); + Qiniu.Init(reader); + _logger.LogInformation("配置加载完成"); } catch (Exception ex) @@ -88,6 +90,43 @@ namespace lai_transfer.Common.Helper } // 存储Origin配置 + + public static class Qiniu + { + public static string AccessKey { get; internal set; } = string.Empty; + public static string SecretKey { get; internal set; } = string.Empty; + public static string BucketName { get; internal set; } = string.Empty; + public static string Domain { get; internal set; } = string.Empty; + public static double MaxFileSize { get; internal set; } = 10; // MB + public static bool OriginImage { get; internal set; } = false; + /// + /// 初始化Qiniu配置 + /// + public static void Init(JsonConfigReader reader) + { + try + { + _logger.LogInformation("正在加载Qiniu配置..."); + // 加载Qiniu配置 + AccessKey = reader.GetString("QiNiu.AccessKey") ?? string.Empty; + SecretKey = reader.GetString("QiNiu.SecretKey") ?? string.Empty; + BucketName = reader.GetString("QiNiu.BucketName") ?? string.Empty; + Domain = reader.GetString("QiNiu.Domain") ?? string.Empty; + MaxFileSize = reader.GetDouble("QiNiu.MaxFileSize") ?? 10; // MB + OriginImage = reader.GetBool("QiNiu.OriginImage") ?? false; + _logger.LogInformation("QiNiu配置加载完成"); + } + catch (Exception ex) + { + _logger.LogError(ex, "加载Qiniu配置失败"); + // 报错,结束程序运行 + throw new InvalidOperationException("无法加载Qiniu配置,请检查配置文件是否存在或格式是否正确。", ex); + } + } + + + } + public static class Origin { // 将private set改为internal set,允许同一程序集中的代码设置属性值 diff --git a/src/Common/Helper/QueryStringHelper.cs b/src/Common/Helper/QueryStringHelper.cs new file mode 100644 index 0000000..3dca810 --- /dev/null +++ b/src/Common/Helper/QueryStringHelper.cs @@ -0,0 +1,132 @@ +namespace lai_transfer.Common.Helper +{ + public static class QueryStringHelper + { + public class ParseResult + { + public string Prefix { get; set; } + public Dictionary Parameters { get; set; } + + public ParseResult() + { + Parameters = new Dictionary(); + } + + // 获取字符串值 + public string GetString(string key, string defaultValue = "") + { + return Parameters.TryGetValue(key, out string value) ? value : defaultValue; + } + + // 获取布尔值 + public bool GetBool(string key, bool defaultValue = false) + { + if (Parameters.TryGetValue(key, out string value)) + { + // 支持多种布尔值格式 + string lowerValue = value.ToLower(); + if (lowerValue == "true" || lowerValue == "1" || lowerValue == "yes") + return true; + if (lowerValue == "false" || lowerValue == "0" || lowerValue == "no") + return false; + } + return defaultValue; + } + + // 获取整数值 + public int GetInt(string key, int defaultValue = 0) + { + if (Parameters.TryGetValue(key, out string value)) + { + if (int.TryParse(value, out int result)) + return result; + } + return defaultValue; + } + + // 获取长整数值 + public long GetLong(string key, long defaultValue = 0) + { + if (Parameters.TryGetValue(key, out string value)) + { + if (long.TryParse(value, out long result)) + return result; + } + return defaultValue; + } + + // 获取双精度浮点数 + public double GetDouble(string key, double defaultValue = 0.0) + { + if (Parameters.TryGetValue(key, out string value)) + { + if (double.TryParse(value, out double result)) + return result; + } + return defaultValue; + } + + // 尝试获取布尔值 + public bool TryGetBool(string key, out bool result) + { + result = false; + if (Parameters.TryGetValue(key, out string value)) + { + string lowerValue = value.ToLower(); + if (lowerValue == "true" || lowerValue == "1" || lowerValue == "yes") + { + result = true; + return true; + } + if (lowerValue == "false" || lowerValue == "0" || lowerValue == "no") + { + result = false; + return true; + } + } + return false; + } + } + + public static ParseResult Parse(string input) + { + var result = new ParseResult(); + + if (string.IsNullOrEmpty(input)) + return result; + + // 找到第一个 ? 的位置 + int firstQuestionMark = input.IndexOf('?'); + + if (firstQuestionMark == -1) + { + // 没有参数,整个字符串都是前缀 + result.Prefix = input; + return result; + } + + // 提取前缀部分(第一个 ? 之前的内容) + result.Prefix = input.Substring(0, firstQuestionMark); + + // 从第一个 ? 之后开始处理参数 + string queryString = input.Substring(firstQuestionMark + 1); + + // 按 ? 分割参数 + var pairs = queryString.Split('?'); + + foreach (var pair in pairs) + { + if (string.IsNullOrWhiteSpace(pair)) + continue; + + var keyValue = pair.Split(new[] { '=' }, 2); + if (keyValue.Length == 2) + { + result.Parameters[keyValue[0]] = keyValue[1]; + } + } + + return result; + } + } +} diff --git a/src/Common/Helper/RetryHelper.cs b/src/Common/Helper/RetryHelper.cs new file mode 100644 index 0000000..eb2b728 --- /dev/null +++ b/src/Common/Helper/RetryHelper.cs @@ -0,0 +1,199 @@ +namespace lai_transfer.Common.Helper; + +public class RetryHelper +{ + private static readonly ILogger _logger = LogHelper.GetLogger(); + /// + /// 异步重试执行函数(无返回值) + /// + /// 要执行的函数 + /// 重试次数 + /// 重试间隔 + /// 取消令牌 + public static async Task RetryAsync( + Func action, + int retryCount = 3, + TimeSpan? delay = null, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(action); + + var exceptions = new List(); + var currentDelay = delay ?? TimeSpan.FromSeconds(1); + + for (int attempt = 0; attempt <= retryCount; attempt++) + { + try + { + if (attempt > 0) + { + _logger?.LogInformation("重试执行,第 {Attempt} 次尝试", attempt); + } + + await action().ConfigureAwait(false); + return; // 执行成功,直接返回 + } + catch (Exception ex) when (ex is not OperationCanceledException) + { + exceptions.Add(ex); + _logger?.LogWarning(ex, "第 {Attempt} 次执行失败", attempt + 1); + + if (attempt == retryCount) + { + throw new AggregateException($"在 {retryCount + 1} 次尝试后操作仍失败", exceptions); + } + + // 等待一段时间后重试 + if (currentDelay > TimeSpan.Zero) + { + _logger?.LogInformation("等待 {Delay} 后重试", currentDelay); + await Task.Delay(currentDelay, cancellationToken).ConfigureAwait(false); + } + } + } + } + + /// + /// 异步重试执行函数(有返回值) + /// + /// 返回值类型 + /// 要执行的函数 + /// 重试次数 + /// 重试间隔(默认1s) + /// 取消令牌 + /// 函数执行结果 + public static async Task RetryAsync( + Func> func, + int retryCount = 3, + TimeSpan? delay = null, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(func); + + var exceptions = new List(); + var currentDelay = delay ?? TimeSpan.FromSeconds(1); + + for (int attempt = 0; attempt <= retryCount; attempt++) + { + try + { + if (attempt > 0) + { + _logger?.LogInformation("重试执行,第 {Attempt} 次尝试", attempt); + } + + return await func().ConfigureAwait(false); + } + catch (Exception ex) when (ex is not OperationCanceledException) + { + exceptions.Add(ex); + _logger?.LogWarning(ex, "第 {Attempt} 次执行失败", attempt + 1); + + if (attempt == retryCount) + { + throw new AggregateException($"在 {retryCount + 1} 次尝试后操作仍失败", exceptions); + } + + // 等待一段时间后重试 + if (currentDelay > TimeSpan.Zero) + { + _logger?.LogInformation("等待 {Delay} 后重试", currentDelay); + await Task.Delay(currentDelay, cancellationToken).ConfigureAwait(false); + } + } + } + + throw new InvalidOperationException("不应该执行到这里"); + } + + /// + /// 同步重试执行函数(无返回值) + /// + public static void Retry( + Action action, + int retryCount = 3, + TimeSpan? delay = null) + { + ArgumentNullException.ThrowIfNull(action); + + var exceptions = new List(); + var currentDelay = delay ?? TimeSpan.FromSeconds(1); + + for (int attempt = 0; attempt <= retryCount; attempt++) + { + try + { + if (attempt > 0) + { + _logger?.LogInformation("重试执行,第 {Attempt} 次尝试", attempt); + } + + action(); + return; // 执行成功,直接返回 + } + catch (Exception ex) + { + exceptions.Add(ex); + _logger?.LogWarning(ex, "第 {Attempt} 次执行失败", attempt + 1); + + if (attempt == retryCount) + { + throw new AggregateException($"在 {retryCount + 1} 次尝试后操作仍失败", exceptions); + } + + // 等待一段时间后重试 + if (currentDelay > TimeSpan.Zero) + { + _logger?.LogInformation("等待 {Delay} 后重试", currentDelay); + Thread.Sleep(currentDelay); + } + } + } + } + + /// + /// 同步重试执行函数(有返回值) + /// + public static TResult Retry( + Func func, + int retryCount = 3, + TimeSpan? delay = null) + { + ArgumentNullException.ThrowIfNull(func); + + var exceptions = new List(); + var currentDelay = delay ?? TimeSpan.FromSeconds(1); + + for (int attempt = 0; attempt <= retryCount; attempt++) + { + try + { + if (attempt > 0) + { + _logger?.LogInformation("重试执行,第 {Attempt} 次尝试", attempt); + } + + return func(); + } + catch (Exception ex) + { + exceptions.Add(ex); + _logger?.LogWarning(ex, "第 {Attempt} 次执行失败", attempt + 1); + + if (attempt == retryCount) + { + throw new AggregateException($"在 {retryCount + 1} 次尝试后操作仍失败", exceptions); + } + + // 等待一段时间后重试 + if (currentDelay > TimeSpan.Zero) + { + _logger?.LogInformation("等待 {Delay} 后重试", currentDelay); + Thread.Sleep(currentDelay); + } + } + } + + throw new InvalidOperationException("不应该执行到这里"); + } +} diff --git a/src/Common/Results/TransferAuthorizationResult.cs b/src/Common/Results/TransferAuthorizationResult.cs index c23c770..8c51520 100644 --- a/src/Common/Results/TransferAuthorizationResult.cs +++ b/src/Common/Results/TransferAuthorizationResult.cs @@ -1,4 +1,22 @@ -namespace lai_transfer.Common.Results +using Newtonsoft.Json.Linq; + +namespace lai_transfer.Common.Results { - public record TransferAuthorizationResult(string Token, string BaseUrl); + public class TransferAuthorizationResult + { + public string Token { get; set; } + public string BaseUrl { get; set; } + public bool Storage { get; set; } + public bool Splice { get; set; } + public string FullPath { get; set; } + + public TransferAuthorizationResult(string Token, string BaseUrl, bool Storage, bool Splice, string FullPath) + { + this.Token = Token; + this.BaseUrl = BaseUrl; + this.Storage = Storage; + this.Splice = Splice; + this.FullPath = FullPath; + } + } } diff --git a/src/Common/Types/MJType.cs b/src/Common/Types/MJType.cs new file mode 100644 index 0000000..bb9fba9 --- /dev/null +++ b/src/Common/Types/MJType.cs @@ -0,0 +1,16 @@ +namespace lai_transfer.Common.Types +{ + public class MJType + { + public class MJOptionType + { + public const string IMAGINE = "IMAGINE"; + + } + + public class MJStatus + { + public const string NOT_START = "not_start"; + } + } +} diff --git a/src/Configuration/DataBase/db.realm b/src/Configuration/DataBase/db.realm new file mode 100644 index 0000000000000000000000000000000000000000..bf00616a6fb2cee98bc2a6b706a1ff01abe02475 GIT binary patch literal 131072 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 private static void AddService(this IServiceCollection services) { + // 注册翻译服务 + services.AddScoped(); + services.AddSingleton(); + services.AddHttpClient(); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + services.AddHostedService(); + if (ConfigHelper.Translate.Model == "GPT") { // 翻译服务注入 diff --git a/src/EndpointServices/MJTransferEndpoint/MJGetFetchIdService.cs b/src/EndpointServices/MJTransferEndpoint/MJGetFetchIdService.cs index e745a43..82a08d7 100644 --- a/src/EndpointServices/MJTransferEndpoint/MJGetFetchIdService.cs +++ b/src/EndpointServices/MJTransferEndpoint/MJGetFetchIdService.cs @@ -2,6 +2,7 @@ using lai_transfer.Common.Helper; using lai_transfer.Common.Results; using lai_transfer.Endpoints; +using lai_transfer.Services.Midjourney; using lai_transfer.Tool.Extensions; using Newtonsoft.Json; @@ -18,16 +19,10 @@ namespace lai_transfer.EndpointServices.MJTransferEndpoint public static async Task Handle(string id, HttpContext httpContext) { - // 先尝试调用原始API - TransferResult? originTransferResult = await TryOriginApiAsync(id); - if (originTransferResult != null) - { - return Results.Text(originTransferResult.Content, originTransferResult.ContentType, statusCode: originTransferResult.StatusCode); - } - // 原始请求失败,请求到指定的API - TransferResult transferResult = await SendUrlTaskFetchById(id, httpContext); - // 返回结果 - return Results.Text(transferResult.Content, transferResult.ContentType, statusCode: transferResult.StatusCode); + TransferAuthorizationResult authorizationResult = httpContext.GetAuthorizationItemsAndValidation(); + authorizationResult.FullPath = httpContext.GetFullRequestPath(); + IMidjourneyService midjourneyService = httpContext.RequestServices.GetRequiredService(); + return await midjourneyService.MidjourneyFetchTaskById(id, authorizationResult); } /// diff --git a/src/EndpointServices/MJTransferEndpoint/MJGetImageSeedService.cs b/src/EndpointServices/MJTransferEndpoint/MJGetImageSeedService.cs index 13c4813..59cf4af 100644 --- a/src/EndpointServices/MJTransferEndpoint/MJGetImageSeedService.cs +++ b/src/EndpointServices/MJTransferEndpoint/MJGetImageSeedService.cs @@ -24,21 +24,26 @@ namespace lai_transfer.EndpointServices.MJTransferEndpoint { try { - //string baseUrl = TransferAuthorizationResult transferAuthorizationResult = httpContext.GetAuthorizationItemsAndValidation(); string url = $"{transferAuthorizationResult.BaseUrl}/mj/task/{id}/image-seed"; - // 设置HttpClient - using HttpClient client = new HttpClient(); - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {transferAuthorizationResult.Token}"); - client.Timeout = Timeout.InfiniteTimeSpan; + TransferResult res = await RetryHelper.RetryAsync(async () => + { + // 设置HttpClient + using HttpClient client = new HttpClient(); + client.DefaultRequestHeaders.Add("Authorization", $"Bearer {transferAuthorizationResult.Token}"); + client.DefaultRequestHeaders.Add("mj-api-secret", transferAuthorizationResult.Token); + client.Timeout = Timeout.InfiniteTimeSpan; - // 发送请求 - var response = await client.GetAsync(url); - string content = await response.Content.ReadAsStringAsync(); + // 发送请求 + var response = await client.GetAsync(url); + string content = await response.Content.ReadAsStringAsync(); - // 返回结果 - return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + // 返回结果 + return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + }, 5); + + return res; } catch (Exception ex) { diff --git a/src/EndpointServices/MJTransferEndpoint/MJPostActionService.cs b/src/EndpointServices/MJTransferEndpoint/MJPostActionService.cs index c4c175c..3a9d92d 100644 --- a/src/EndpointServices/MJTransferEndpoint/MJPostActionService.cs +++ b/src/EndpointServices/MJTransferEndpoint/MJPostActionService.cs @@ -27,16 +27,22 @@ namespace lai_transfer.EndpointServices.MJTransferEndpoint { TransferAuthorizationResult authorizationResult = httpContext.GetAuthorizationItemsAndValidation(); string url = $"{authorizationResult.BaseUrl}/mj/submit/action"; - // 设置HttpClient - using HttpClient client = new HttpClient(); - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {authorizationResult.Token}"); - client.Timeout = Timeout.InfiniteTimeSpan; - string body = JSONHelper.RemoveJsonProperties(model, "notifyHook"); - // 发送请求 - var response = await client.PostAsync(url, new StringContent(body, System.Text.Encoding.UTF8, "application/json")); - string content = await response.Content.ReadAsStringAsync(); - return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + TransferResult res = await RetryHelper.RetryAsync(async () => + { + // 设置HttpClient + using HttpClient client = new HttpClient(); + client.DefaultRequestHeaders.Add("Authorization", $"Bearer {authorizationResult.Token}"); + client.DefaultRequestHeaders.Add("mj-api-secret", authorizationResult.Token); + client.Timeout = Timeout.InfiniteTimeSpan; + + string body = JSONHelper.RemoveJsonProperties(model, "notifyHook"); + // 发送请求 + var response = await client.PostAsync(url, new StringContent(body, System.Text.Encoding.UTF8, "application/json")); + string content = await response.Content.ReadAsStringAsync(); + return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + }, 5); + return res; } catch (Exception ex) { diff --git a/src/EndpointServices/MJTransferEndpoint/MJPostBlendService.cs b/src/EndpointServices/MJTransferEndpoint/MJPostBlendService.cs index 102d491..39b2e58 100644 --- a/src/EndpointServices/MJTransferEndpoint/MJPostBlendService.cs +++ b/src/EndpointServices/MJTransferEndpoint/MJPostBlendService.cs @@ -26,17 +26,22 @@ namespace lai_transfer.EndpointServices.MJTransferEndpoint { TransferAuthorizationResult authorizationResult = httpContext.GetAuthorizationItemsAndValidation(); string url = $"{authorizationResult.BaseUrl}/mj/submit/blend"; - // 设置HttpClient - using HttpClient client = new HttpClient(); - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {authorizationResult.Token}"); - client.Timeout = Timeout.InfiniteTimeSpan; - // 删除回调参数 notifyHook - string body = JSONHelper.RemoveJsonProperties(model, "notifyHook"); - // 发送请求 - var response = await client.PostAsync(url, new StringContent(body, System.Text.Encoding.UTF8, "application/json")); - string content = await response.Content.ReadAsStringAsync(); + TransferResult res = await RetryHelper.RetryAsync(async () => + { + // 设置HttpClient + using HttpClient client = new HttpClient(); + client.DefaultRequestHeaders.Add("Authorization", $"Bearer {authorizationResult.Token}"); + client.DefaultRequestHeaders.Add("mj-api-secret", authorizationResult.Token); + client.Timeout = Timeout.InfiniteTimeSpan; + // 删除回调参数 notifyHook + string body = JSONHelper.RemoveJsonProperties(model, "notifyHook"); + // 发送请求 + var response = await client.PostAsync(url, new StringContent(body, System.Text.Encoding.UTF8, "application/json")); + string content = await response.Content.ReadAsStringAsync(); - return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + }, 5); + return res; } catch (Exception ex) { diff --git a/src/EndpointServices/MJTransferEndpoint/MJPostDescribeService.cs b/src/EndpointServices/MJTransferEndpoint/MJPostDescribeService.cs index 35e937f..1936ff6 100644 --- a/src/EndpointServices/MJTransferEndpoint/MJPostDescribeService.cs +++ b/src/EndpointServices/MJTransferEndpoint/MJPostDescribeService.cs @@ -26,18 +26,23 @@ namespace lai_transfer.EndpointServices.MJTransferEndpoint { TransferAuthorizationResult authorizationResult = httpContext.GetAuthorizationItemsAndValidation(); string url = $"{authorizationResult.BaseUrl}/mj/submit/describe"; - // 设置HttpClient - using HttpClient client = new HttpClient(); - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {authorizationResult.Token}"); - client.Timeout = Timeout.InfiniteTimeSpan; + TransferResult res = await RetryHelper.RetryAsync(async () => + { + // 设置HttpClient + using HttpClient client = new HttpClient(); + client.DefaultRequestHeaders.Add("Authorization", $"Bearer {authorizationResult.Token}"); + client.DefaultRequestHeaders.Add("mj-api-secret", authorizationResult.Token); + client.Timeout = Timeout.InfiniteTimeSpan; - // 删除回调参数 notifyHook - string body = JSONHelper.RemoveJsonProperties(model, "notifyHook"); - // 发送请求 - var response = await client.PostAsync(url, new StringContent(body, System.Text.Encoding.UTF8, "application/json")); - string content = await response.Content.ReadAsStringAsync(); + // 删除回调参数 notifyHook + string body = JSONHelper.RemoveJsonProperties(model, "notifyHook"); + // 发送请求 + var response = await client.PostAsync(url, new StringContent(body, System.Text.Encoding.UTF8, "application/json")); + string content = await response.Content.ReadAsStringAsync(); - return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + }, 5); + return res; } catch (Exception ex) { diff --git a/src/EndpointServices/MJTransferEndpoint/MJPostFetchListByConditionService.cs b/src/EndpointServices/MJTransferEndpoint/MJPostFetchListByConditionService.cs index 56aaf61..304d05e 100644 --- a/src/EndpointServices/MJTransferEndpoint/MJPostFetchListByConditionService.cs +++ b/src/EndpointServices/MJTransferEndpoint/MJPostFetchListByConditionService.cs @@ -2,10 +2,8 @@ using lai_transfer.Common.Helper; using lai_transfer.Common.Results; using lai_transfer.Endpoints; -using lai_transfer.Tool.Extensions; -using Microsoft.AspNetCore.Authorization; -using Newtonsoft.Json; -using System.Text.Json; +using lai_transfer.Services.Midjourney; +using static lai_transfer.Model.Midjourney.MidjourneyRequest; namespace lai_transfer.EndpointServices.MJTransferEndpoint { @@ -17,133 +15,13 @@ namespace lai_transfer.EndpointServices.MJTransferEndpoint .WithSummary("Midjourney 根据ID列表查询任务") .WithMJAuthorizationHeader(); - private static async Task Handle(JsonElement model, HttpContext httpContext) + private static async Task Handle(FetchListByCondition model, HttpContext httpContext) { + TransferAuthorizationResult transferAuthorizationResult = httpContext.GetAuthorizationItemsAndValidation(); - // 先尝试调用原始API - TransferResult? originTransferResult = await TryOriginApiAsync(model); - if (originTransferResult != null) - { - return Results.Text(originTransferResult.Content, originTransferResult.ContentType, statusCode: originTransferResult.StatusCode); - } + IMidjourneyService midjourneyService = httpContext.RequestServices.GetRequiredService(); - TransferResult transferResult = await SendOriginalFetchListByCondition(model, httpContext); - return Results.Text(transferResult.Content, transferResult.ContentType, statusCode: transferResult.StatusCode); - } - - private static async Task SendOriginalFetchListByCondition(JsonElement model, HttpContext httpContext) - { - try - { - TransferAuthorizationResult transferAuthorizationResult = httpContext.GetAuthorizationItemsAndValidation(); - string url = $"{transferAuthorizationResult.BaseUrl}/mj/task/list-by-condition"; - // 设置HttpClient - using HttpClient client = new HttpClient(); - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {transferAuthorizationResult.Token}"); - client.Timeout = Timeout.InfiniteTimeSpan; - - string body = model.GetRawText(); - // 发送请求 - var response = await client.PostAsync(url, new StringContent(body, System.Text.Encoding.UTF8, "application/json")); - string content = await response.Content.ReadAsStringAsync(); - return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); - } - catch (Exception ex) - { - _logger.LogError(ex, $"转发 {httpContext.GetFullRequestPath()} 失败"); - // 处理异常,返回错误信息 - return new TransferResult(ex.Message, "application/json", StatusCodes.Status500InternalServerError); - } - } - - /// - /// 获取原始数据信息 bzu - /// - /// - /// - private static async Task TryOriginApiAsync(JsonElement model) - { - // 如果要访问任意JSON节点,可以使用JsonConfigReader - //var reader = new JsonConfigReader("Configuration/config/transfer.json"); - string? baseUrl = ConfigHelper.Origin.BaseUrl; - string? token = ConfigHelper.Origin.Token; - - if (string.IsNullOrWhiteSpace(baseUrl) || string.IsNullOrWhiteSpace(token)) - { - _logger.LogWarning("配置文件中未找到 Origin.BaseUrl 或 Origin.Token"); - return null; - } - - string originUrl = $"{baseUrl.TrimEnd('/')}/mj/task/list-by-condition"; - - try - { - using var client = new HttpClient(); - client.DefaultRequestHeaders.Add("Authorization", token); - client.Timeout = TimeSpan.FromSeconds(30); - - string body = model.GetRawText(); - var response = await client.PostAsync(originUrl, new StringContent(body, System.Text.Encoding.UTF8, "application/json")); - var content = await response.Content.ReadAsStringAsync(); - - // 判断是不是返回空 - if ((int)response.StatusCode == 204 || string.IsNullOrWhiteSpace(content)) - { - return null; - } - if (!response.IsSuccessStatusCode) - { - _logger.LogWarning($"源API调用 /mj/task/list-by-condition 返回错误状态码, StatusCode: {response.StatusCode}"); - return null; - } - - // 有返回结果 这这边开始处理返回的数据信息 - List>? properties = ProcessTaskArrayData(content); - if (properties != null && properties.Count > 0) - { - return new TransferResult( - JsonConvert.SerializeObject(properties), - "application/json", - StatusCodes.Status200OK); - } - else - { - return null; - } - } - catch (Exception ex) - { - _logger.LogWarning(ex, "原始API /mj/task/list-by-condition 调用失败"); - return null; - } - } - - private static List>? ProcessTaskArrayData(string content) - { - try - { - List> result = []; - // 解析 JSON 数据 - var jsonObject = JsonConvert.DeserializeObject>>(content); - if (jsonObject == null || jsonObject.Count == 0) - { - return []; - } - // 处理每个任务数据 - for (int i = 0; i < jsonObject.Count; i++) - { - var properties = MJGetFetchIdService.ProcessTaskObjectData(jsonObject[i]); - result.Add(properties); - } - - // 返回数据 - return result; - } - catch (Exception ex) - { - _logger.LogError(ex, "处理任务数据失败"); - return null; - } + return await midjourneyService.FetchListByCondition(model, transferAuthorizationResult); } } } diff --git a/src/EndpointServices/MJTransferEndpoint/MJPostImagineService.cs b/src/EndpointServices/MJTransferEndpoint/MJPostImagineService.cs index d417159..26292ce 100644 --- a/src/EndpointServices/MJTransferEndpoint/MJPostImagineService.cs +++ b/src/EndpointServices/MJTransferEndpoint/MJPostImagineService.cs @@ -2,7 +2,8 @@ using lai_transfer.Common.Helper; using lai_transfer.Common.Results; using lai_transfer.Endpoints; -using lai_transfer.Services; +using lai_transfer.Services.Midjourney; +using lai_transfer.Services.Translate; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; @@ -20,8 +21,7 @@ namespace lai_transfer.EndpointServices.MJTransferEndpoint private static async Task Handle(JsonElement model, HttpContext httpContext) { - (string content, string contentType, int statusCode) = await SendOriginalImagine(model, httpContext); - return Results.Text(content, contentType, statusCode: statusCode); + return await SendOriginalImagine(model, httpContext); } /// @@ -30,111 +30,23 @@ namespace lai_transfer.EndpointServices.MJTransferEndpoint /// /// /// - private static async Task<(string content, string contentType, int statusCode)> SendOriginalImagine(JsonElement model, HttpContext httpContext) + private static async Task SendOriginalImagine(JsonElement model, HttpContext httpContext) { try { TransferAuthorizationResult authorizationResult = httpContext.GetAuthorizationItemsAndValidation(); - string url = $"{authorizationResult.BaseUrl}/mj/submit/imagine"; + string requestUrl = httpContext.GetFullRequestPath(); + authorizationResult.FullPath = requestUrl; + IMidjourneyService midjourneyService = httpContext.RequestServices.GetRequiredService(); - // 设置HttpClient - using HttpClient client = new HttpClient(); - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {authorizationResult.Token}"); - client.Timeout = Timeout.InfiniteTimeSpan; - - // 强制翻译提示词 - string prompt = JSONHelper.GetJsonPropertyString(model, "prompt") ?? string.Empty; - - // 使用HttpContext扩展方法获取翻译服务 - var translateService = ServiceLocator.GetRequiredService(); - prompt = await TranslatePrompt(prompt, translateService); - - model = JSONHelper.SetJsonProperty(model, "prompt", prompt); - - // 删除回调参数 notifyHook - string body = JSONHelper.RemoveJsonProperties(model, "notifyHook"); - //return (body, "application/json", 200); - // 发送请求 - var response = await client.PostAsync(url, new StringContent(body, Encoding.UTF8, "application/json")); - string content = await response.Content.ReadAsStringAsync(); - return (content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + IResult t = await midjourneyService.MidjourneyImagine(model, authorizationResult); + return t; } catch (Exception ex) { _logger.LogError(ex, $"请求 {httpContext.GetFullRequestPath()} 失败"); // 处理异常,返回错误信息 - return (ex.Message, "application/json", StatusCodes.Status500InternalServerError); - } - } - - /// - /// 翻译提示词 - /// - /// 原始提示词 - /// 翻译服务 - /// 翻译后的提示词 - public static async Task TranslatePrompt(string prompt, ITranslateService translateService) - { - if (string.IsNullOrWhiteSpace(prompt)) - return prompt; - - try - { - - // 检查是否启用翻译功能 - if (!ConfigHelper.Translate.Enable) - return prompt; - - // 如果不包含中文,直接返回 - if (string.IsNullOrWhiteSpace(prompt) || !translateService.ContainsChinese(prompt)) - return prompt; - - string paramStr = ""; - var paramMatcher = Regex.Match(prompt, "\\x20+--[a-z]+.*$", RegexOptions.IgnoreCase); - if (paramMatcher.Success) - { - paramStr = paramMatcher.Value; - } - string promptWithoutParam = prompt.Substring(0, prompt.Length - paramStr.Length); - List imageUrls = new List(); - var imageMatcher = Regex.Matches(promptWithoutParam, "https?://[a-z0-9-_:@&?=+,.!/~*'%$]+\\x20+", RegexOptions.IgnoreCase); - foreach (Match match in imageMatcher) - { - imageUrls.Add(match.Value); - } - string text = promptWithoutParam; - foreach (string imageUrl in imageUrls) - { - text = text.Replace(imageUrl, ""); - } - text = text.Trim(); - if (!string.IsNullOrWhiteSpace(text)) - { - text = await translateService.TranslateToEnglish(text); - } - if (!string.IsNullOrWhiteSpace(paramStr)) - { - // 当有 --no 参数时, 翻译 --no 参数, 并替换原参数 - // --sref https://mjcdn.googlec.cc/1.jpg --no aa, bb, cc - var paramNomatcher = Regex.Match(paramStr, "--no\\s+(.*?)(?=--|$)"); - if (paramNomatcher.Success) - { - string paramNoStr = paramNomatcher.Groups[1].Value.Trim(); - string paramNoStrEn = await translateService.TranslateToEnglish(paramNoStr); - - // 提取 --no 之前的参数 - paramStr = paramStr.Substring(0, paramNomatcher.Index); - - // 替换 --no 参数 - paramStr = paramStr + paramNomatcher.Result("--no " + paramNoStrEn + " "); - } - } - return string.Concat(imageUrls) + text.Trim() + paramStr; - } - catch (Exception ex) - { - LogHelper.LogError(ex, "翻译提示词失败,使用原始提示词"); - return prompt; + return Results.BadRequest("request error : " + ex.Message); } } } diff --git a/src/EndpointServices/MJTransferEndpoint/MJPostModalService.cs b/src/EndpointServices/MJTransferEndpoint/MJPostModalService.cs index 75bbbab..1cb6594 100644 --- a/src/EndpointServices/MJTransferEndpoint/MJPostModalService.cs +++ b/src/EndpointServices/MJTransferEndpoint/MJPostModalService.cs @@ -2,7 +2,8 @@ using lai_transfer.Common.Helper; using lai_transfer.Common.Results; using lai_transfer.Endpoints; -using lai_transfer.Services; +using lai_transfer.Services.Translate; +using Microsoft.AspNetCore.Authorization; using System.Text.Json; namespace lai_transfer.EndpointServices.MJTransferEndpoint @@ -27,26 +28,35 @@ namespace lai_transfer.EndpointServices.MJTransferEndpoint { TransferAuthorizationResult transferAuthorizationResult = httpContext.GetAuthorizationItemsAndValidation(); string url = $"{transferAuthorizationResult.BaseUrl}/mj/submit/modal"; - // 设置HttpClient - using HttpClient client = new HttpClient(); - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {transferAuthorizationResult.Token}"); - client.Timeout = Timeout.InfiniteTimeSpan; // 强制翻译提示词 string prompt = JSONHelper.GetJsonPropertyString(model, "prompt") ?? string.Empty; + if (string.IsNullOrWhiteSpace(prompt)) + { + prompt = JSONHelper.GetJsonPropertyString(model, "Prompt") ?? string.Empty; + } // 使用HttpContext扩展方法获取翻译服务 - var translateService = ServiceLocator.GetRequiredService(); - prompt = await MJPostImagineService.TranslatePrompt(prompt, translateService); + var translateService = ServiceLocator.GetRequiredService(); + prompt = await translateService.TranslatePrompt(prompt); model = JSONHelper.SetJsonProperty(model, "prompt", prompt); // 删除回调参数 notifyHook string body = JSONHelper.RemoveJsonProperties(model, "notifyHook"); - // 发送请求 - var response = await client.PostAsync(url, new StringContent(body, System.Text.Encoding.UTF8, "application/json")); - string content = await response.Content.ReadAsStringAsync(); - return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + + TransferResult res = await RetryHelper.RetryAsync(async () => + { + // 设置HttpClient + using HttpClient client = new HttpClient(); + client.DefaultRequestHeaders.Add("Authorization", $"Bearer {transferAuthorizationResult.Token}"); + client.DefaultRequestHeaders.Add("mj-api-secret", transferAuthorizationResult.Token); + client.Timeout = Timeout.InfiniteTimeSpan; + var response = await client.PostAsync(url, new StringContent(body, System.Text.Encoding.UTF8, "application/json")); + string content = await response.Content.ReadAsStringAsync(); + return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + }, 5); + return res; } catch (Exception ex) { diff --git a/src/EndpointServices/MJTransferEndpoint/MJPostShortenService.cs b/src/EndpointServices/MJTransferEndpoint/MJPostShortenService.cs index 1d08e93..c237998 100644 --- a/src/EndpointServices/MJTransferEndpoint/MJPostShortenService.cs +++ b/src/EndpointServices/MJTransferEndpoint/MJPostShortenService.cs @@ -2,6 +2,7 @@ using lai_transfer.Common.Helper; using lai_transfer.Common.Results; using lai_transfer.Endpoints; +using Microsoft.AspNetCore.Authorization; using System.Text.Json; namespace lai_transfer.EndpointServices.MJTransferEndpoint @@ -26,17 +27,22 @@ namespace lai_transfer.EndpointServices.MJTransferEndpoint { TransferAuthorizationResult transferAuthorizationResult = httpContext.GetAuthorizationItemsAndValidation(); string url = $"{transferAuthorizationResult.BaseUrl}/mj/submit/shorten"; - - // 设置HttpClient - using HttpClient client = new HttpClient(); - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {transferAuthorizationResult.Token}"); - client.Timeout = Timeout.InfiniteTimeSpan; // 删除回调参数 notifyHook string body = JSONHelper.RemoveJsonProperties(model, "notifyHook"); - // 发送请求 - var response = await client.PostAsync(url, new StringContent(body, System.Text.Encoding.UTF8, "application/json")); - string content = await response.Content.ReadAsStringAsync(); - return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + + TransferResult res = await RetryHelper.RetryAsync(async () => + { + // 设置HttpClient + using HttpClient client = new HttpClient(); + client.DefaultRequestHeaders.Add("Authorization", $"Bearer {transferAuthorizationResult.Token}"); + client.DefaultRequestHeaders.Add("mj-api-secret", transferAuthorizationResult.Token); + client.Timeout = Timeout.InfiniteTimeSpan; + // 发送请求 + var response = await client.PostAsync(url, new StringContent(body, System.Text.Encoding.UTF8, "application/json")); + string content = await response.Content.ReadAsStringAsync(); + return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + }, 5); + return res; } catch (Exception ex) { diff --git a/src/EndpointServices/MJTransferEndpoint/MJPostSwapFaceService.cs b/src/EndpointServices/MJTransferEndpoint/MJPostSwapFaceService.cs index 9d82bb6..24aab98 100644 --- a/src/EndpointServices/MJTransferEndpoint/MJPostSwapFaceService.cs +++ b/src/EndpointServices/MJTransferEndpoint/MJPostSwapFaceService.cs @@ -2,6 +2,7 @@ using lai_transfer.Common.Helper; using lai_transfer.Common.Results; using lai_transfer.Endpoints; +using Microsoft.AspNetCore.Authorization; using System.Text.Json; namespace lai_transfer.EndpointServices.MJTransferEndpoint @@ -26,17 +27,22 @@ namespace lai_transfer.EndpointServices.MJTransferEndpoint { TransferAuthorizationResult transferAuthorizationResult = httpContext.GetAuthorizationItemsAndValidation(); string url = $"{transferAuthorizationResult.BaseUrl}/mj/insight-face/swap"; - - // 设置HttpClient - using HttpClient client = new(); - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {transferAuthorizationResult.Token}"); - client.Timeout = Timeout.InfiniteTimeSpan; // 删除回调参数 notifyHook string body = JSONHelper.RemoveJsonProperties(model, "notifyHook"); - // 发送请求 - var response = await client.PostAsync(url, new StringContent(body, System.Text.Encoding.UTF8, "application/json")); - string content = await response.Content.ReadAsStringAsync(); - return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + + TransferResult res = await RetryHelper.RetryAsync(async () => + { + // 设置HttpClient + using HttpClient client = new(); + client.DefaultRequestHeaders.Add("Authorization", $"Bearer {transferAuthorizationResult.Token}"); + client.DefaultRequestHeaders.Add("mj-api-secret", transferAuthorizationResult.Token); + client.Timeout = Timeout.InfiniteTimeSpan; + // 发送请求 + var response = await client.PostAsync(url, new StringContent(body, System.Text.Encoding.UTF8, "application/json")); + string content = await response.Content.ReadAsStringAsync(); + return new TransferResult(content, response.Content.Headers.ContentType?.ToString() ?? "application/json", (int)response.StatusCode); + }, 5); + return res; } catch (Exception ex) { diff --git a/src/Examples/ServiceUsageExamples.cs b/src/Examples/ServiceUsageExamples.cs deleted file mode 100644 index 23cdd7b..0000000 --- a/src/Examples/ServiceUsageExamples.cs +++ /dev/null @@ -1,88 +0,0 @@ -using lai_transfer.Common.Extensions; -using lai_transfer.Common.Helper; -using lai_transfer.Services; -using System.Threading.Tasks; - -namespace lai_transfer.Examples -{ - /// - /// չʾʹ÷ȡչʾ - /// - public static class ServiceUsageExamples - { - /// - /// HttpContextijʹ÷ - /// - /// Http - public static async Task ExampleWithHttpContext(HttpContext httpContext) - { - // ʽ1ʹHttpContextչȡ - var translateService = httpContext.GetRequiredService(); - var loggerFactory = httpContext.GetService(); - var logger = loggerFactory?.CreateLogger("ServiceUsageExamples"); - - // ʹ÷ - string result = await translateService.TranslateToEnglish(""); - logger?.LogInformation($": {result}"); - } - - /// - /// ûHttpContextijʹ÷羲̨̬ȣ - /// - public static async Task ExampleWithoutHttpContext() - { - // ʽ2ʹȫַλȡ - var translateService = ServiceLocator.GetRequiredService(); - var loggerFactory = ServiceLocator.GetService(); - var logger = loggerFactory?.CreateLogger("ServiceUsageExamples"); - - // ʹ÷ - string result = await translateService.TranslateToEnglish(""); - logger?.LogInformation($": {result}"); - } - - /// - /// Ҫijʹ - /// - public static async Task ExampleWithScope() - { - // µ - using var scope = ServiceLocator.CreateScope(); - var scopedServices = scope.ServiceProvider; - - // лȡ - var translateService = scopedServices.GetRequiredService(); - - // ʹ÷ - string result = await translateService.TranslateToEnglish(""); - - // ʱԶͷԴ - } - - /// - /// ڶ˵㴦еʹʾ - /// - public static async Task EndpointExample(HttpContext httpContext) - { - try - { - // ֱӴHttpContextȡڷ - var translateService = httpContext.GetRequiredService(); - var loggerFactory = httpContext.GetRequiredService(); - var logger = loggerFactory.CreateLogger("ServiceUsageExamples"); - - // ҵ߼ - string prompt = "ı"; - string translatedPrompt = await translateService.TranslateToEnglish(prompt); - - logger.LogInformation($": {prompt} -> {translatedPrompt}"); - - return Results.Ok(new { original = prompt, translated = translatedPrompt }); - } - catch (Exception ex) - { - return Results.Problem($"ʧ: {ex.Message}"); - } - } - } -} \ No newline at end of file diff --git a/src/FodyWeavers.xml b/src/FodyWeavers.xml new file mode 100644 index 0000000..cc07b89 --- /dev/null +++ b/src/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/Model/Entity/MJTask.cs b/src/Model/Entity/MJTask.cs new file mode 100644 index 0000000..bad84b7 --- /dev/null +++ b/src/Model/Entity/MJTask.cs @@ -0,0 +1,59 @@ +using lai_transfer.Tool.Extensions; +using Realms; + +namespace lai_transfer.Model.Entity +{ + [MapTo("MJTask")] + public class MJTask : RealmObject + { + [PrimaryKey] + [MapTo("_id")] + public string ID { get; set; } = string.Empty; + + [MapTo("mjId")] + public string MJId { get; set; } + + [MapTo("type")] + public string Type { get; set; } + + [MapTo("status")] + public string Status { get; set; } + + [MapTo("baseUrl")] + public string BaseUrl { get; set; } + + [MapTo("property")] + public string Property { get; set; } + + [MapTo("authorizationResult")] + public string AuthorizationResult { get; set; } + + [MapTo("createdTime")] + public DateTimeOffset CreatedTime { get; set; } = BeijingTimeExtension.GetBeijingTime(); + + [MapTo("checkedTime")] + public DateTimeOffset CheckedTime { get; set; } = BeijingTimeExtension.GetBeijingTime(); + } + + public class MJTaskDTO + { + + public string ID { get; set; } = string.Empty; + + public string MJId { get; set; } + + public string Type { get; set; } + + public string Status { get; set; } + + public string BaseUrl { get; set; } + + public string Property { get; set; } + + public string AuthorizationResult { get; set; } + + public DateTimeOffset CreatedTime { get; set; } = BeijingTimeExtension.GetBeijingTime(); + + public DateTimeOffset CheckedTime { get; set; } = BeijingTimeExtension.GetBeijingTime(); + } +} diff --git a/src/Model/Midjourney/MidjourneyRequest.cs b/src/Model/Midjourney/MidjourneyRequest.cs new file mode 100644 index 0000000..6d23d93 --- /dev/null +++ b/src/Model/Midjourney/MidjourneyRequest.cs @@ -0,0 +1,10 @@ +namespace lai_transfer.Model.Midjourney +{ + public class MidjourneyRequest + { + public class FetchListByCondition + { + public List Ids { get; set; } = []; + } + } +} diff --git a/src/Model/Midjourney/MidjourneyTaskResponse.cs b/src/Model/Midjourney/MidjourneyTaskResponse.cs new file mode 100644 index 0000000..8fbc5e7 --- /dev/null +++ b/src/Model/Midjourney/MidjourneyTaskResponse.cs @@ -0,0 +1,158 @@ +using System.Text.Json.Serialization; + +namespace lai_transfer.Model.Midjourney +{ + public class MidjourneyTaskResponse + { + + public class TaskResponse + { + [JsonPropertyName("id")] + public string Id { get; set; } + + [JsonPropertyName("accountId")] + public string AccountId { get; set; } + + [JsonPropertyName("action")] + public string Action { get; set; } + + [JsonPropertyName("status")] + public string Status { get; set; } + + [JsonPropertyName("mode")] + public string Mode { get; set; } + + [JsonPropertyName("prompt")] + public string Prompt { get; set; } + + [JsonPropertyName("promptEn")] + public string PromptEn { get; set; } + + [JsonPropertyName("description")] + public string Description { get; set; } + + [JsonPropertyName("submitTime")] + public long? SubmitTime { get; set; } + + [JsonPropertyName("startTime")] + public long? StartTime { get; set; } + + [JsonPropertyName("finishTime")] + public long? FinishTime { get; set; } + + [JsonPropertyName("progress")] + public string Progress { get; set; } + + [JsonPropertyName("imageUrl")] + public string ImageUrl { get; set; } + + [JsonPropertyName("imageUrls")] + public List ImageUrls { get; set; } + + [JsonPropertyName("videoUrl")] + public string? VideoUrl { get; set; } + + [JsonPropertyName("videoUrls")] + public object? VideoUrls { get; set; } + + [JsonPropertyName("imageHeight")] + public int? ImageHeight { get; set; } + + [JsonPropertyName("imageWidth")] + public int? ImageWidth { get; set; } + + [JsonPropertyName("failReason")] + public string? FailReason { get; set; } + + [JsonPropertyName("notifyHook")] + public string NotifyHook { get; set; } + + [JsonPropertyName("state")] + public object? State { get; set; } + + [JsonPropertyName("buttons")] + public List