diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Embeddings/EmbeddingCreateRequest.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Embeddings/EmbeddingCreateRequest.cs
new file mode 100644
index 00000000..b5dec5a8
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Embeddings/EmbeddingCreateRequest.cs
@@ -0,0 +1,79 @@
+using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
+
+namespace Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Embeddings;
+
+//TODO add model validation
+//TODO check what is string or array for prompt,..
+public record EmbeddingCreateRequest
+{
+ ///
+ /// Input text to get embeddings for, encoded as a string or array of tokens. To get embeddings for multiple inputs
+ /// in a single request, pass an array of strings or array of token arrays. Each input must not exceed 2048 tokens in
+ /// length.
+ /// Unless your are embedding code, we suggest replacing newlines (`\n`) in your input with a single space, as we have
+ /// observed inferior results when newlines are present.
+ ///
+ ///
+ [JsonIgnore]
+ public List? InputAsList { get; set; }
+
+ ///
+ /// Input text to get embeddings for, encoded as a string or array of tokens. To get embeddings for multiple inputs
+ /// in a single request, pass an array of strings or array of token arrays. Each input must not exceed 2048 tokens in
+ /// length.
+ /// Unless your are embedding code, we suggest replacing newlines (`\n`) in your input with a single space, as we have
+ /// observed inferior results when newlines are present.
+ ///
+ ///
+ [JsonIgnore]
+ public string? Input { get; set; }
+
+
+ [JsonPropertyName("input")]
+ public IList? InputCalculated
+ {
+ get
+ {
+ if (Input != null && InputAsList != null)
+ {
+ throw new ValidationException(
+ "Input and InputAsList can not be assigned at the same time. One of them is should be null.");
+ }
+
+ if (Input != null)
+ {
+ return new List { Input };
+ }
+
+ return InputAsList;
+ }
+ }
+
+ ///
+ /// ID of the model to use. You can use the [List models](/docs/api-reference/models/list) API to see all of your
+ /// available models, or see our [Model overview](/docs/models/overview) for descriptions of them.
+ ///
+ ///
+ [JsonPropertyName("model")]
+ public string? Model { get; set; }
+
+ ///
+ /// The number of dimensions the resulting output embeddings should have. Only supported in text-embedding-3 and later models.
+ ///
+ ///
+ [JsonPropertyName("dimensions")]
+ public int? Dimensions { get; set; }
+
+ ///
+ /// The format to return the embeddings in. Can be either float or base64.
+ ///
+ ///
+ [JsonPropertyName("encoding_format")]
+ public string? EncodingFormat { get; set; }
+
+ public IEnumerable Validate()
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Embeddings/EmbeddingCreateResponse.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Embeddings/EmbeddingCreateResponse.cs
new file mode 100644
index 00000000..6558cfbd
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Embeddings/EmbeddingCreateResponse.cs
@@ -0,0 +1,111 @@
+using System.Buffers;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Embeddings;
+
+public record EmbeddingCreateResponse : ThorBaseResponse
+{
+ [JsonPropertyName("model")] public string Model { get; set; }
+
+ [JsonPropertyName("data")] public List Data { get; set; } = [];
+
+ ///
+ /// 类型转换,如果类型是base64,则将float[]转换为base64,如果是空或是float和原始类型一样,则不转换
+ ///
+ public void ConvertEmbeddingData(string? encodingFormat)
+ {
+ if (Data.Count == 0)
+ {
+ return;
+ }
+
+ switch (encodingFormat)
+ {
+ // 判断第一个是否是float[],如果是则不转换
+ case null or "float" when Data[0].Embedding is float[]:
+ return;
+ // 否则转换成float[]
+ case null or "float":
+ {
+ foreach (var embeddingResponse in Data)
+ {
+ if (embeddingResponse.Embedding is string base64)
+ {
+ embeddingResponse.Embedding = Convert.FromBase64String(base64);
+ }
+ }
+
+ return;
+ }
+ // 判断第一个是否是string,如果是则不转换
+ case "base64" when Data[0].Embedding is string:
+ return;
+ // 否则转换成base64
+ case "base64":
+ {
+ foreach (var embeddingResponse in Data)
+ {
+ if (embeddingResponse.Embedding is JsonElement str)
+ {
+ if (str.ValueKind == JsonValueKind.Array)
+ {
+ var floats = str.EnumerateArray().Select(element => element.GetSingle()).ToArray();
+
+ embeddingResponse.Embedding = ConvertFloatArrayToBase64(floats);
+ }
+ }
+ else if (embeddingResponse.Embedding is IList doubles)
+ {
+ embeddingResponse.Embedding = ConvertFloatArrayToBase64(doubles.ToArray());
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ public static string ConvertFloatArrayToBase64(double[] floatArray)
+ {
+ // 将 float[] 转换成 byte[]
+ byte[] byteArray = ArrayPool.Shared.Rent(floatArray.Length * sizeof(float));
+ try
+ {
+ Buffer.BlockCopy(floatArray, 0, byteArray, 0, byteArray.Length);
+
+ // 将 byte[] 转换成 base64 字符串
+ return Convert.ToBase64String(byteArray);
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(byteArray);
+ }
+ }
+
+ public static string ConvertFloatArrayToBase64(float[] floatArray)
+ {
+ // 将 float[] 转换成 byte[]
+ byte[] byteArray = ArrayPool.Shared.Rent(floatArray.Length * sizeof(float));
+ try
+ {
+ Buffer.BlockCopy(floatArray, 0, byteArray, 0, floatArray.Length);
+
+ // 将 byte[] 转换成 base64 字符串
+ return Convert.ToBase64String(byteArray);
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(byteArray);
+ }
+ }
+
+ [JsonPropertyName("usage")] public ThorUsageResponse? Usage { get; set; }
+}
+
+public record EmbeddingResponse
+{
+ [JsonPropertyName("index")] public int? Index { get; set; }
+
+ [JsonPropertyName("embedding")] public object Embedding { get; set; }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Embeddings/ThorEmbeddingInput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Embeddings/ThorEmbeddingInput.cs
new file mode 100644
index 00000000..f6f1a0c0
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Embeddings/ThorEmbeddingInput.cs
@@ -0,0 +1,22 @@
+using System.Text.Json.Serialization;
+
+namespace Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Embeddings;
+
+public sealed class ThorEmbeddingInput
+{
+ [JsonPropertyName("model")]
+ public string Model { get; set; }
+
+ [JsonPropertyName("input")]
+ public object Input { get; set; }
+
+ [JsonPropertyName("encoding_format")]
+ public string EncodingFormat { get; set; }
+
+ [JsonPropertyName("dimensions")]
+ public int? Dimensions { get; set; }
+
+ [JsonPropertyName("user")]
+ public string? User { get; set; }
+}
+
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/ThorChatMessage.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/ThorChatMessage.cs
index 7ec811e2..62c9edc4 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/ThorChatMessage.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/ThorChatMessage.cs
@@ -14,7 +14,6 @@ public class ThorChatMessage
///
public ThorChatMessage()
{
-
}
///
@@ -74,20 +73,19 @@ public class ThorChatMessage
{
if (value is JsonElement str)
{
- if (str.ValueKind == JsonValueKind.String)
- {
- Content = value?.ToString();
- }
- else if (str.ValueKind == JsonValueKind.Array)
+ if (str.ValueKind == JsonValueKind.Array)
{
Contents = JsonSerializer.Deserialize>(value?.ToString());
}
}
+ else if (value is string strInput)
+ {
+ Content = strInput;
+ }
else
{
Content = value?.ToString();
}
-
}
}
@@ -108,15 +106,14 @@ public class ThorChatMessage
///
[JsonPropertyName("function_call")]
public ThorChatMessageFunction? FunctionCall { get; set; }
-
+
///
/// 【可选】推理内容
///
[JsonPropertyName("reasoning_content")]
public string? ReasoningContent { get; set; }
-
- [JsonPropertyName("id")]
- public string? Id { get; set; }
+
+ [JsonPropertyName("id")] public string? Id { get; set; }
///
/// 工具调用列表,模型生成的工具调用,例如函数调用。
@@ -164,14 +161,15 @@ public class ThorChatMessage
/// 参与者的可选名称。提供模型信息以区分同一角色的参与者。
/// 工具调用参数列表
///
- public static ThorChatMessage CreateAssistantMessage(string content, string? name = null, List toolCalls = null)
+ public static ThorChatMessage CreateAssistantMessage(string content, string? name = null,
+ List toolCalls = null)
{
return new()
{
Role = ThorChatMessageRoleConst.Assistant,
Content = content,
Name = name,
- ToolCalls=toolCalls,
+ ToolCalls = toolCalls,
};
}
@@ -187,7 +185,7 @@ public class ThorChatMessage
{
Role = ThorChatMessageRoleConst.Tool,
Content = content,
- ToolCallId= toolCallId
+ ToolCallId = toolCallId
};
}
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs
index 08c6a233..d67f7934 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs
@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Volo.Abp.Application.Services;
using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi;
+using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Embeddings;
using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
using Yi.Framework.AiHub.Domain.Entities.Model;
using Yi.Framework.AiHub.Domain.Extensions;
@@ -72,6 +73,20 @@ public class OpenApiService : ApplicationService
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
await _aiGateWayManager.CreateImageForStatisticsAsync(httpContext, userId, null, input);
}
+
+ ///
+ /// 向量生成
+ ///
+ ///
+ ///
+ [HttpPost("openApi/v1/embeddings")]
+ public async Task EmbeddingAsync([FromBody] ThorEmbeddingInput input, CancellationToken cancellationToken)
+ {
+ var httpContext = this._httpContextAccessor.HttpContext;
+ var userId = await _tokenManager.GetUserIdAsync(GetTokenByHttpContext(httpContext));
+ await _aiBlacklistManager.VerifiyAiBlacklist(userId);
+ await _aiGateWayManager.EmbeddingForStatisticsAsync(httpContext, userId, null, input);
+ }
///
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/ModelTypeEnum.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/ModelTypeEnum.cs
index e1167ce2..1e4fbd33 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/ModelTypeEnum.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/ModelTypeEnum.cs
@@ -1,8 +1,8 @@
namespace Yi.Framework.AiHub.Domain.Shared.Enums;
-
public enum ModelTypeEnum
{
Chat = 0,
- Image = 1
+ Image = 1,
+ Embedding = 2
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/ITextEmbeddingService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/ITextEmbeddingService.cs
new file mode 100644
index 00000000..8911fbf1
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/ITextEmbeddingService.cs
@@ -0,0 +1,19 @@
+using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Embeddings;
+using Yi.Framework.AiHub.Domain.Shared.Dtos;
+
+namespace Yi.Framework.AiHub.Domain.AiGateWay;
+
+public interface ITextEmbeddingService
+{
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task EmbeddingAsync(
+ EmbeddingCreateRequest createEmbeddingModel,
+ AiModelDescribe? aiModelDescribe = null,
+ CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/Impl/ThorSiliconFlow/Embeddings/SiliconFlowTextEmbeddingService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/Impl/ThorSiliconFlow/Embeddings/SiliconFlowTextEmbeddingService.cs
new file mode 100644
index 00000000..42b25fd9
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/Impl/ThorSiliconFlow/Embeddings/SiliconFlowTextEmbeddingService.cs
@@ -0,0 +1,24 @@
+using System.Net.Http.Json;
+using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Embeddings;
+using Yi.Framework.AiHub.Domain.Shared.Dtos;
+
+namespace Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorSiliconFlow.Embeddings;
+
+public sealed class SiliconFlowTextEmbeddingService
+ : ITextEmbeddingService
+{
+ public async Task EmbeddingAsync(
+ EmbeddingCreateRequest createEmbeddingModel,
+ AiModelDescribe? options = null,
+ CancellationToken cancellationToken = default)
+ {
+ var response = await HttpClientFactory.GetHttpClient(options.Endpoint).PostJsonAsync(
+ options?.Endpoint.TrimEnd('/') + "/v1/embeddings",
+ createEmbeddingModel, options!.ApiKey);
+
+ var result =
+ await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken);
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs
index 042693a5..37c6a8c0 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs
@@ -2,6 +2,7 @@ using System.Collections.Concurrent;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;
+using System.Text.Json;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -10,6 +11,7 @@ using Newtonsoft.Json.Serialization;
using Volo.Abp.Domain.Services;
using Yi.Framework.AiHub.Application.Contracts.Dtos;
using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi;
+using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Embeddings;
using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
using Yi.Framework.AiHub.Domain.AiGateWay;
using Yi.Framework.AiHub.Domain.AiGateWay.Exceptions;
@@ -276,19 +278,20 @@ public class AiGateWayManager : DomainService
///
///
///
- public async Task CreateImageForStatisticsAsync(HttpContext context,Guid? userId,Guid? sessionId, ImageCreateRequest request)
+ public async Task CreateImageForStatisticsAsync(HttpContext context, Guid? userId, Guid? sessionId,
+ ImageCreateRequest request)
{
try
{
var model = request.Model;
if (string.IsNullOrEmpty(model)) model = "dall-e-2";
-
+
var modelDescribe = await GetModelAsync(model);
-
+
// 获取渠道指定的实现类型的服务
var imageService =
LazyServiceProvider.GetRequiredKeyedService(modelDescribe.HandlerName);
-
+
var response = await imageService.CreateImage(request, modelDescribe);
if (response.Error != null || response.Results.Count == 0)
@@ -297,7 +300,7 @@ public class AiGateWayManager : DomainService
}
await context.Response.WriteAsJsonAsync(response);
-
+
await _aiMessageManager.CreateUserMessageAsync(userId, sessionId,
new MessageInputDto
{
@@ -322,4 +325,110 @@ public class AiGateWayManager : DomainService
throw new UserFriendlyException(errorContent);
}
}
+
+
+ ///
+ /// 向量生成
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task EmbeddingForStatisticsAsync(HttpContext context, Guid? userId, Guid? sessionId,
+ ThorEmbeddingInput input)
+ {
+ try
+ {
+ if (input == null) throw new Exception("模型校验异常");
+
+ using var embedding =
+ Activity.Current?.Source.StartActivity("向量模型调用");
+
+ var modelDescribe = await GetModelAsync(input.Model);
+
+ // 获取渠道指定的实现类型的服务
+ var embeddingService =
+ LazyServiceProvider.GetRequiredKeyedService(modelDescribe.HandlerName);
+
+ var embeddingCreateRequest = new EmbeddingCreateRequest
+ {
+ Model = input.Model,
+ EncodingFormat = input.EncodingFormat
+ };
+
+ //dto进行转换,支持多种格式
+ if (input.Input is JsonElement str)
+ {
+ if (str.ValueKind == JsonValueKind.Array)
+ {
+ var inputString = str.EnumerateArray().Select(x => x.ToString()).ToArray();
+ embeddingCreateRequest.InputAsList = inputString.ToList();
+ }
+ else
+ {
+ throw new Exception("Input,输入格式错误,非string或Array类型");
+ }
+ }
+ else if (input.Input is string strInput)
+ {
+ embeddingCreateRequest.Input = strInput;
+ }
+ else
+ {
+ throw new Exception("Input,输入格式错误,未找到类型");
+ }
+
+
+ var stream =
+ await embeddingService.EmbeddingAsync(embeddingCreateRequest, modelDescribe, context.RequestAborted);
+
+ var usage = new ThorUsageResponse()
+ {
+ InputTokens = stream.Usage?.InputTokens ?? 0,
+ CompletionTokens = 0,
+ TotalTokens = stream.Usage?.InputTokens ?? 0
+ };
+ await context.Response.WriteAsJsonAsync(new
+ {
+ input.Model,
+ stream.Data,
+ stream.Error,
+ stream.ObjectTypeName,
+ Usage = usage
+ });
+
+ await _aiMessageManager.CreateUserMessageAsync(userId, sessionId,
+ new MessageInputDto
+ {
+ Content = string.Empty,
+ ModelId = input.Model,
+ TokenUsage = usage,
+ });
+
+ await _aiMessageManager.CreateSystemMessageAsync(userId, sessionId,
+ new MessageInputDto
+ {
+ Content = string.Empty,
+ ModelId = input.Model,
+ TokenUsage = usage
+ });
+
+ await _usageStatisticsManager.SetUsageAsync(userId, input.Model, usage);
+ }
+ catch (ThorRateLimitException)
+ {
+ context.Response.StatusCode = 429;
+ }
+ catch (UnauthorizedAccessException e)
+ {
+ context.Response.StatusCode = 401;
+ }
+ catch (Exception e)
+ {
+ var errorContent = $"嵌入Ai异常,异常信息:\n当前Ai模型:{input.Model}\n异常信息:{e.Message}\n异常堆栈:{e}";
+ throw new UserFriendlyException(errorContent);
+ }
+ }
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Yi.Framework.AiHub.Domain.csproj b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Yi.Framework.AiHub.Domain.csproj
index 17f70e7b..34f50862 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Yi.Framework.AiHub.Domain.csproj
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Yi.Framework.AiHub.Domain.csproj
@@ -13,4 +13,8 @@
+
+
+
+
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/YiFrameworkAiHubDomainModule.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/YiFrameworkAiHubDomainModule.cs
index f143e6c9..eca30868 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/YiFrameworkAiHubDomainModule.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/YiFrameworkAiHubDomainModule.cs
@@ -7,6 +7,7 @@ using Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorAzureDatabricks.Chats;
using Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorAzureOpenAI.Chats;
using Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorAzureOpenAI.Images;
using Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorDeepSeek.Chats;
+using Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorSiliconFlow.Embeddings;
using Yi.Framework.AiHub.Domain.Shared;
using Yi.Framework.Mapster;
@@ -35,6 +36,8 @@ namespace Yi.Framework.AiHub.Domain
services.AddKeyedTransient(
nameof(AzureOpenAIServiceImageService));
+
+ services.AddKeyedTransient(nameof(SiliconFlowTextEmbeddingService));
//ai模型特殊性兼容处理
Configure(options =>