mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-12 23:33:48 +00:00
Classify embedding failures at the provider level
This commit is contained in:
11 files changed
+230
-36
No files matched your search
@@ -215,7 +215,21 @@ public partial class SettingsPanelEmbeddings : SettingsPanelProviderBase
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var embeddingProvider = provider.CreateProvider();
|
var embeddingProvider = provider.CreateProvider();
|
||||||
var embeddings = await embeddingProvider.EmbedTextAsync(provider.Model, this.SettingsManager, CancellationToken.None, inputText);
|
IReadOnlyList<IReadOnlyList<float>> embeddings;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
embeddings = await embeddingProvider.EmbedTextAsync(provider.Model, this.SettingsManager, CancellationToken.None, inputText);
|
||||||
|
}
|
||||||
|
catch (ProviderRequestException exception)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// The provider named what went wrong and what to do about it. Showing that beats the
|
||||||
|
// sentence below, which used to be the same one for a missing API key, an unreachable
|
||||||
|
// provider and a provider which cannot embed anything at all:
|
||||||
|
//
|
||||||
|
await this.DialogService.ShowMessageBox(T("Embedding Result"), exception.UserMessage, T("Close"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (embeddings.Count == 0)
|
if (embeddings.Count == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, n
|
|||||||
/// <inhertidoc />
|
/// <inhertidoc />
|
||||||
public override Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
public override Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||||
{
|
{
|
||||||
return Task.FromResult<IReadOnlyList<IReadOnlyList<float>>>([]);
|
throw this.CreateEmbeddingsNotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -238,9 +238,106 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
protected virtual string GetProviderRequestFailureUserMessage(ProviderRequestFailureReason failureReason) => failureReason switch
|
protected virtual string GetProviderRequestFailureUserMessage(ProviderRequestFailureReason failureReason) => failureReason switch
|
||||||
{
|
{
|
||||||
ProviderRequestFailureReason.TOO_MANY_REQUESTS => TB("The provider rejected the request because too many requests were sent. Please wait a moment and try again."),
|
ProviderRequestFailureReason.TOO_MANY_REQUESTS => TB("The provider rejected the request because too many requests were sent. Please wait a moment and try again."),
|
||||||
|
ProviderRequestFailureReason.INVALID_OR_MISSING_API_KEY => string.Format(TB("The API key for the provider '{0}' is missing or was rejected. Please check the key in the settings."), this.InstanceName),
|
||||||
|
ProviderRequestFailureReason.AUTHENTICATION_OR_PERMISSION_ERROR => string.Format(TB("The provider '{0}' refused the request. Your account might not be allowed to use the selected model, or the provider might not serve your region."), this.InstanceName),
|
||||||
|
ProviderRequestFailureReason.PROVIDER_UNAVAILABLE => string.Format(TB("The provider '{0}' could not be reached. Please check whether it is running and reachable, then try again."), this.InstanceName),
|
||||||
|
ProviderRequestFailureReason.MODEL_NOT_FOUND => string.Format(TB("The provider '{0}' does not know the selected model. Please select another model."), this.InstanceName),
|
||||||
|
ProviderRequestFailureReason.CONTEXT_LENGTH_EXCEEDED => TB("The text was longer than the selected model accepts. Please select a model which takes longer texts, or reduce the chunk size of the data source."),
|
||||||
|
ProviderRequestFailureReason.EMBEDDINGS_NOT_SUPPORTED => string.Format(TB("The provider '{0}' cannot create embeddings. Please select a provider which offers an embedding model."), this.InstanceName),
|
||||||
|
ProviderRequestFailureReason.INVALID_RESPONSE => string.Format(TB("The provider '{0}' sent an answer AI Studio was not able to read."), this.InstanceName),
|
||||||
_ => string.Empty,
|
_ => string.Empty,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds the failure a provider reports when it offers no embeddings at all.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Such a provider used to answer with an empty list, which the caller was not able to tell
|
||||||
|
/// apart from a provider which simply produced nothing this time. Saying it outright is what
|
||||||
|
/// lets the user go and pick a provider which can do the job.
|
||||||
|
/// </remarks>
|
||||||
|
protected ProviderRequestException CreateEmbeddingsNotSupportedException() => new(ProviderRequestFailureReason.EMBEDDINGS_NOT_SUPPORTED,
|
||||||
|
this.GetProviderRequestFailureUserMessage(ProviderRequestFailureReason.EMBEDDINGS_NOT_SUPPORTED));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds the failure of an embedding request the provider answered with an error.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Shared with the providers which talk to an embedding endpoint of their own: what the user
|
||||||
|
/// needs to know does not depend on which route the request took.
|
||||||
|
/// </remarks>
|
||||||
|
protected ProviderRequestException CreateEmbeddingRequestException(HttpStatusCode statusCode, string reasonPhrase, string responseBody)
|
||||||
|
{
|
||||||
|
var failureReason = this.ClassifyEmbeddingRequestFailure(statusCode, responseBody);
|
||||||
|
var userMessage = this.GetProviderRequestFailureUserMessage(failureReason);
|
||||||
|
|
||||||
|
// We know nothing about this failure, so we pass on what the provider said about it:
|
||||||
|
if (string.IsNullOrWhiteSpace(userMessage))
|
||||||
|
{
|
||||||
|
var providerMessage = ReadProviderErrorMessage(responseBody);
|
||||||
|
userMessage = string.IsNullOrWhiteSpace(providerMessage)
|
||||||
|
? string.Format(TB("The provider '{0}' rejected the embedding request with the status code {1}."), this.InstanceName, (int)statusCode)
|
||||||
|
: string.Format(TB("The provider '{0}' reported an error: {1}"), this.InstanceName, providerMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new(failureReason, userMessage, statusCode, reasonPhrase, responseBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds the failure of an embedding request which did not get an answer at all.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exception">What went wrong while the request was on its way.</param>
|
||||||
|
/// <param name="isTimeout">Whether the provider took longer than we were willing to wait.</param>
|
||||||
|
protected ProviderRequestException CreateEmbeddingRequestException(Exception exception, bool isTimeout)
|
||||||
|
{
|
||||||
|
if (isTimeout)
|
||||||
|
return new(ProviderRequestFailureReason.PROVIDER_UNAVAILABLE, this.GetProviderRequestFailureUserMessage(ProviderRequestFailureReason.PROVIDER_UNAVAILABLE), responseBody: exception.Message);
|
||||||
|
|
||||||
|
return new(ProviderRequestFailureReason.UNKNOWN, string.Format(TB("The embedding request to the provider '{0}' failed: {1}"), this.InstanceName, exception.Message), responseBody: exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Classifies why an embedding request failed.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Kept apart from the chat classification on purpose. The chat path turns most failures into
|
||||||
|
/// a message and carries on, so classifying more cases there would change what every user
|
||||||
|
/// sees. The embedding path has no such fallback: it either produces vectors or it fails, and
|
||||||
|
/// then the caller has to be able to say why.
|
||||||
|
/// </remarks>
|
||||||
|
private ProviderRequestFailureReason ClassifyEmbeddingRequestFailure(HttpStatusCode statusCode, string responseBody)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Whatever the shared classification recognizes wins: it knows what a provider says about
|
||||||
|
// quota and rate limits, and several providers refine it for their own error format.
|
||||||
|
//
|
||||||
|
var sharedFailureReason = this.ClassifyProviderRequestFailure(statusCode, responseBody);
|
||||||
|
if (sharedFailureReason is not ProviderRequestFailureReason.NONE)
|
||||||
|
return sharedFailureReason;
|
||||||
|
|
||||||
|
return statusCode switch
|
||||||
|
{
|
||||||
|
HttpStatusCode.Unauthorized => ProviderRequestFailureReason.INVALID_OR_MISSING_API_KEY,
|
||||||
|
HttpStatusCode.Forbidden => ProviderRequestFailureReason.AUTHENTICATION_OR_PERMISSION_ERROR,
|
||||||
|
HttpStatusCode.NotFound => ProviderRequestFailureReason.MODEL_NOT_FOUND,
|
||||||
|
HttpStatusCode.RequestEntityTooLarge => ProviderRequestFailureReason.CONTEXT_LENGTH_EXCEEDED,
|
||||||
|
HttpStatusCode.BadRequest when IsContextLengthFailure(responseBody) => ProviderRequestFailureReason.CONTEXT_LENGTH_EXCEEDED,
|
||||||
|
HttpStatusCode.RequestTimeout or HttpStatusCode.InternalServerError or HttpStatusCode.BadGateway or HttpStatusCode.ServiceUnavailable or HttpStatusCode.GatewayTimeout => ProviderRequestFailureReason.PROVIDER_UNAVAILABLE,
|
||||||
|
_ => ProviderRequestFailureReason.UNKNOWN,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Recognizes the answer a provider gives when the text was longer than the model accepts.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// There is no common error code for this. What the answers have in common is that they talk
|
||||||
|
/// about the context and about tokens, which is the same hint the chat path goes by.
|
||||||
|
/// </remarks>
|
||||||
|
private static bool IsContextLengthFailure(string responseBody) =>
|
||||||
|
responseBody.Contains("context", StringComparison.InvariantCultureIgnoreCase) &&
|
||||||
|
responseBody.Contains("token", StringComparison.InvariantCultureIgnoreCase);
|
||||||
|
|
||||||
protected virtual ProviderRequestFailureReason ClassifyProviderRequestFailure(HttpStatusCode statusCode, string responseBody)
|
protected virtual ProviderRequestFailureReason ClassifyProviderRequestFailure(HttpStatusCode statusCode, string responseBody)
|
||||||
{
|
{
|
||||||
if (statusCode is not HttpStatusCode.TooManyRequests)
|
if (statusCode is not HttpStatusCode.TooManyRequests)
|
||||||
@@ -401,7 +498,14 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="responseBody">The body of the failed response.</param>
|
/// <param name="responseBody">The body of the failed response.</param>
|
||||||
/// <returns>The message, or an empty string when the body carries none.</returns>
|
/// <returns>The message, or an empty string when the body carries none.</returns>
|
||||||
private static string ReadProviderErrorMessage(string responseBody)
|
/// <summary>
|
||||||
|
/// Reads what the provider itself said about a failure out of its error response.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Available to the providers because some of them talk to an endpoint of their own rather
|
||||||
|
/// than through the shared request methods, and their users deserve the same explanation.
|
||||||
|
/// </remarks>
|
||||||
|
protected static string ReadProviderErrorMessage(string responseBody)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(responseBody))
|
if (string.IsNullOrWhiteSpace(responseBody))
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
@@ -1339,9 +1443,9 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
if(!requestedSecret.Success)
|
if(!requestedSecret.Success)
|
||||||
{
|
{
|
||||||
this.logger.LogError("No valid API key available for embedding request.");
|
this.logger.LogError("No valid API key available for embedding request.");
|
||||||
return [];
|
throw new ProviderRequestException(ProviderRequestFailureReason.INVALID_OR_MISSING_API_KEY, this.GetProviderRequestFailureUserMessage(ProviderRequestFailureReason.INVALID_OR_MISSING_API_KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1354,21 +1458,13 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
if (!response.IsSuccessStatusCode)
|
if (!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
this.logger.LogError("Embedding request failed with status code {ResponseStatusCode} and body: '{ResponseBody}'.", response.StatusCode, responseBody);
|
this.logger.LogError("Embedding request failed with status code {ResponseStatusCode} and body: '{ResponseBody}'.", response.StatusCode, responseBody);
|
||||||
var providerRequestFailure = this.ClassifyProviderRequestFailure(response.StatusCode, responseBody);
|
|
||||||
var userMessage = this.GetProviderRequestFailureUserMessage(providerRequestFailure);
|
|
||||||
|
|
||||||
// We know nothing about this failure, so we pass on what the provider said about it:
|
//
|
||||||
if (string.IsNullOrWhiteSpace(userMessage))
|
// Thrown instead of shown: the caller knows whether this is one file out of
|
||||||
{
|
// thousands being indexed in the background or the one thing the user just asked
|
||||||
var providerMessage = ReadProviderErrorMessage(responseBody);
|
// for, and only it can decide how often the user should hear about it.
|
||||||
if (!string.IsNullOrWhiteSpace(providerMessage))
|
//
|
||||||
userMessage = string.Format(TB("The provider '{0}' reported an error: {1}"), this.InstanceName, providerMessage);
|
throw this.CreateEmbeddingRequestException(response.StatusCode, response.ReasonPhrase ?? string.Empty, responseBody);
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(userMessage))
|
|
||||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.CloudOff, userMessage));
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var embeddingResponse = JsonSerializer.Deserialize<EmbeddingResponse>(responseBody, JSON_SERIALIZER_OPTIONS);
|
var embeddingResponse = JsonSerializer.Deserialize<EmbeddingResponse>(responseBody, JSON_SERIALIZER_OPTIONS);
|
||||||
@@ -1382,16 +1478,32 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.logger.LogError("Was not able to deserialize the embedding response.");
|
this.logger.LogError("Was not able to deserialize the embedding response.");
|
||||||
return [];
|
throw new ProviderRequestException(ProviderRequestFailureReason.INVALID_RESPONSE, this.GetProviderRequestFailureUserMessage(ProviderRequestFailureReason.INVALID_RESPONSE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (ProviderRequestException)
|
||||||
|
{
|
||||||
|
// Already classified and carrying its user message. Wrapping it again would only
|
||||||
|
// replace what we know with the fact that something went wrong:
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// The caller stopped the work, e.g. because the user removed the data source while it
|
||||||
|
// was being indexed. That is not a failure of the provider and must not be recorded
|
||||||
|
// as one:
|
||||||
|
//
|
||||||
|
throw;
|
||||||
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if (this.IsTimeoutException(e, token))
|
var isTimeout = this.IsTimeoutException(e, token);
|
||||||
|
if (isTimeout)
|
||||||
await this.SendTimeoutError("creating embeddings");
|
await this.SendTimeoutError("creating embeddings");
|
||||||
|
|
||||||
this.logger.LogError("Failed to perform embedding request: '{Message}'.", e.Message);
|
this.logger.LogError("Failed to perform embedding request: '{Message}'.", e.Message);
|
||||||
return [];
|
throw this.CreateEmbeddingRequestException(e, isTimeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public sealed class ProviderDeepSeek() : BaseProvider(LLMProviders.DEEP_SEEK, ne
|
|||||||
/// <inhertidoc />
|
/// <inhertidoc />
|
||||||
public override Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
public override Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||||
{
|
{
|
||||||
return Task.FromResult<IReadOnlyList<IReadOnlyList<float>>>([]);
|
throw this.CreateEmbeddingsNotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public class ProviderFireworks() : BaseProvider(LLMProviders.FIREWORKS, new Uri(
|
|||||||
/// <inhertidoc />
|
/// <inhertidoc />
|
||||||
public override Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
public override Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||||
{
|
{
|
||||||
return Task.FromResult<IReadOnlyList<IReadOnlyList<float>>>([]);
|
throw this.CreateEmbeddingsNotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -79,16 +79,16 @@ public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, new Uri("https
|
|||||||
if (string.IsNullOrWhiteSpace(modelName))
|
if (string.IsNullOrWhiteSpace(modelName))
|
||||||
{
|
{
|
||||||
LOGGER.LogError("No model name provided for embedding request.");
|
LOGGER.LogError("No model name provided for embedding request.");
|
||||||
return [];
|
throw new ProviderRequestException(ProviderRequestFailureReason.MODEL_NOT_FOUND, this.GetProviderRequestFailureUserMessage(ProviderRequestFailureReason.MODEL_NOT_FOUND));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modelName.StartsWith("models/", StringComparison.OrdinalIgnoreCase))
|
if (modelName.StartsWith("models/", StringComparison.OrdinalIgnoreCase))
|
||||||
modelName = modelName.Substring("models/".Length);
|
modelName = modelName["models/".Length..];
|
||||||
|
|
||||||
if (!requestedSecret.Success)
|
if (!requestedSecret.Success)
|
||||||
{
|
{
|
||||||
LOGGER.LogError("No valid API key available for embedding request.");
|
LOGGER.LogError("No valid API key available for embedding request.");
|
||||||
return [];
|
throw new ProviderRequestException(ProviderRequestFailureReason.INVALID_OR_MISSING_API_KEY, this.GetProviderRequestFailureUserMessage(ProviderRequestFailureReason.INVALID_OR_MISSING_API_KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the Google Gemini embedding request:
|
// Prepare the Google Gemini embedding request:
|
||||||
@@ -116,7 +116,7 @@ public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, new Uri("https
|
|||||||
if (!response.IsSuccessStatusCode)
|
if (!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
LOGGER.LogError("Embedding request failed with status code {ResponseStatusCode} and body: '{ResponseBody}'.", response.StatusCode, responseBody);
|
LOGGER.LogError("Embedding request failed with status code {ResponseStatusCode} and body: '{ResponseBody}'.", response.StatusCode, responseBody);
|
||||||
return [];
|
throw this.CreateEmbeddingRequestException(response.StatusCode, response.ReasonPhrase ?? string.Empty, responseBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
var embeddingResponse = JsonSerializer.Deserialize<GoogleEmbeddingResponse>(responseBody, JSON_SERIALIZER_OPTIONS);
|
var embeddingResponse = JsonSerializer.Deserialize<GoogleEmbeddingResponse>(responseBody, JSON_SERIALIZER_OPTIONS);
|
||||||
@@ -130,17 +130,33 @@ public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, new Uri("https
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOGGER.LogError("Was not able to deserialize the embedding response.");
|
LOGGER.LogError("Was not able to deserialize the embedding response.");
|
||||||
return [];
|
throw new ProviderRequestException(ProviderRequestFailureReason.INVALID_RESPONSE, this.GetProviderRequestFailureUserMessage(ProviderRequestFailureReason.INVALID_RESPONSE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (ProviderRequestException)
|
||||||
|
{
|
||||||
|
// Already classified and carrying its user message. Wrapping it again would only
|
||||||
|
// replace what we know with the fact that something went wrong:
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// The caller stopped the work, e.g. because the user removed the data source while it
|
||||||
|
// was being indexed. That is not a failure of the provider and must not be recorded
|
||||||
|
// as one:
|
||||||
|
//
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if (this.IsTimeoutException(e, token))
|
var isTimeout = this.IsTimeoutException(e, token);
|
||||||
|
if (isTimeout)
|
||||||
await this.SendTimeoutError("creating embeddings");
|
await this.SendTimeoutError("creating embeddings");
|
||||||
|
|
||||||
LOGGER.LogError("Failed to perform embedding request: '{Message}'.", e.Message);
|
LOGGER.LogError("Failed to perform embedding request: '{Message}'.", e.Message);
|
||||||
return [];
|
throw this.CreateEmbeddingRequestException(e, isTimeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ public class ProviderGroq() : BaseProvider(LLMProviders.GROQ, new Uri("https://a
|
|||||||
/// <inhertidoc />
|
/// <inhertidoc />
|
||||||
public override Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
public override Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||||
{
|
{
|
||||||
return Task.FromResult<IReadOnlyList<IReadOnlyList<float>>>([]);
|
throw this.CreateEmbeddingsNotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public sealed class ProviderHetzner() : BaseProvider(LLMProviders.HETZNER, new U
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
public override Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||||
{
|
{
|
||||||
return Task.FromResult<IReadOnlyList<IReadOnlyList<float>>>([]);
|
throw this.CreateEmbeddingsNotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public sealed class ProviderPerplexity() : BaseProvider(LLMProviders.PERPLEXITY,
|
|||||||
/// <inhertidoc />
|
/// <inhertidoc />
|
||||||
public override Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
public override Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||||
{
|
{
|
||||||
return Task.FromResult<IReadOnlyList<IReadOnlyList<float>>>([]);
|
throw this.CreateEmbeddingsNotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -14,4 +14,56 @@ public enum ProviderRequestFailureReason
|
|||||||
/// meant to answer for it does not offer it.
|
/// meant to answer for it does not offer it.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
MODEL_NOT_SUPPORTED_BY_PROVIDER,
|
MODEL_NOT_SUPPORTED_BY_PROVIDER,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// No usable API key was available, or the provider rejected the one we sent.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Both cases lead to the same place for the user: the key stored for this provider is not
|
||||||
|
/// one the provider works with, and the settings are where they fix it.
|
||||||
|
/// </remarks>
|
||||||
|
INVALID_OR_MISSING_API_KEY,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The key was accepted, but the account is not allowed to do what we asked for.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Typical causes are a key without the required scope, a model the account has no access
|
||||||
|
/// to, and providers which refuse requests from the user's region.
|
||||||
|
/// </remarks>
|
||||||
|
AUTHENTICATION_OR_PERMISSION_ERROR,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The provider could not be reached, or said that it cannot serve requests right now.
|
||||||
|
/// </summary>
|
||||||
|
PROVIDER_UNAVAILABLE,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The provider does not know the requested model at all.
|
||||||
|
/// </summary>
|
||||||
|
MODEL_NOT_FOUND,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The text we sent was longer than the model accepts.
|
||||||
|
/// </summary>
|
||||||
|
CONTEXT_LENGTH_EXCEEDED,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The provider cannot create embeddings at all.
|
||||||
|
/// </summary>
|
||||||
|
EMBEDDINGS_NOT_SUPPORTED,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The provider answered successfully, but with something we were not able to read.
|
||||||
|
/// </summary>
|
||||||
|
INVALID_RESPONSE,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The request failed and we were not able to tell why.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Deliberately without a user message of its own: what the provider itself said about the
|
||||||
|
/// failure tells the user more than a sentence which says nothing.
|
||||||
|
/// </remarks>
|
||||||
|
UNKNOWN,
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ public sealed class ProviderX() : BaseProvider(LLMProviders.X, new Uri("https://
|
|||||||
/// <inhertidoc />
|
/// <inhertidoc />
|
||||||
public override Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
public override Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||||
{
|
{
|
||||||
return Task.FromResult<IReadOnlyList<IReadOnlyList<float>>>([]);
|
throw this.CreateEmbeddingsNotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
Reference in new issue
Block a user