🌐 AI搜索 & 代理 主页
Skip to content

Commit 32e4a0d

Browse files
committed
feat: Add TokenPony provider (ID=19) and refactor Azure/ChatService architecture
New Provider: - Added TokenPony (ID=19) model provider - Default URL: https://api.tokenpony.cn/v1 - Added tokenpony.svg icon - Added Chinese translation: 小马算力 Azure Rebranding: - Renamed DBModelProvider.AzureOpenAI to AzureAIFoundry (ID=1) - Renamed AzureChatCompletionService to AzureAIFoundryChatService - Updated to use azure-ai-foundry.svg icon (removed old azure-openai.svg) - Azure services now auto-append /openai/v1/ to URLs if not present ChatService Architecture Improvements: - Removed suggestedApiUrl parameter from all ChatService constructors - Simplified URL fallback: ModelKey.Host -> ModelProviderInfo.GetInitialHost - Removed empty ChatService implementations (DeepSeek, Doubao, MiniMax, Kimi, Ollama, Xunfei) - ChatFactory now fallbacks to ChatCompletionService for unknown providers - Extracted Azure Host transformation to shared CreateTransformedModelKey method - Deduplicated code in AzureResponseApiService and AzureImageGenerationService Breaking Changes: - Enum value AzureOpenAI changed to AzureAIFoundry across frontend and backend
1 parent ba8122c commit 32e4a0d

32 files changed

+173
-126
lines changed

src/BE/DB/Enums/DBModelProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
public enum DBModelProvider
44
{
55
Test = 0,
6-
AzureOpenAI = 1,
6+
AzureAIFoundry = 1,
77
HunYuan = 2,
88
LingYi = 3,
99
Moonshot = 4,
@@ -21,4 +21,5 @@ public enum DBModelProvider
2121
Doubao = 16,
2222
SiliconFlow = 17,
2323
OpenRouter = 18,
24+
TokenPony = 19,
2425
}

src/BE/DB/ModelProviderInfo.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ private record ProviderInfo(
2222
null,
2323
null
2424
),
25-
[DBModelProvider.AzureOpenAI] = new(
26-
DBModelProvider.AzureOpenAI,
27-
"Azure OpenAI",
28-
"https://<resource-name>.openai.azure.com/",
25+
[DBModelProvider.AzureAIFoundry] = new(
26+
DBModelProvider.AzureAIFoundry,
27+
"Azure AI Foundry",
28+
"https://yourresource.openai.azure.com/openai/v1/",
2929
""
3030
),
3131
[DBModelProvider.HunYuan] = new(
@@ -130,6 +130,12 @@ private record ProviderInfo(
130130
"https://openrouter.ai/api/v1",
131131
"sk-or-v1-***"
132132
),
133+
[DBModelProvider.TokenPony] = new(
134+
DBModelProvider.TokenPony,
135+
"Token Pony",
136+
"https://api.tokenpony.cn/v1",
137+
"sk-"
138+
),
133139
};
134140

135141
private static readonly Dictionary<string, DBModelProvider> _nameToIdMap = _providers

src/BE/Services/Models/ChatServices/ChatFactory.cs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,38 +31,31 @@ public ChatService CreateChatService(Model model)
3131
DBApiType.ImageGeneration => modelProvider switch
3232
{
3333
DBModelProvider.OpenAI => new ImageGenerationService(model),
34-
DBModelProvider.AzureOpenAI => new AzureImageGenerationService(model),
34+
DBModelProvider.AzureAIFoundry => new AzureImageGenerationService(model),
3535
_ => new ImageGenerationService(model) // Fallback to OpenAI-compatible
3636
},
3737

3838
DBApiType.Response => modelProvider switch
3939
{
4040
DBModelProvider.OpenAI => new ResponseApiService(model, logger),
41-
DBModelProvider.AzureOpenAI => new AzureResponseApiService(model, logger),
41+
DBModelProvider.AzureAIFoundry => new AzureResponseApiService(model, logger),
4242
_ => new ResponseApiService(model, logger) // Fallback to OpenAI-compatible
4343
},
4444

4545
DBApiType.ChatCompletion => modelProvider switch
4646
{
47-
DBModelProvider.OpenAI => new ChatCompletionService(model),
48-
DBModelProvider.AzureOpenAI => new AzureChatCompletionService(model),
47+
DBModelProvider.AzureAIFoundry => new AzureAIFoundryChatService(model),
4948
DBModelProvider.WenXinQianFan => new QianFanChatService(model),
5049
DBModelProvider.AliyunDashscope => new QwenChatService(model),
5150
DBModelProvider.ZhiPuAI => new GLMChatService(model),
52-
DBModelProvider.Moonshot => new KimiChatService(model),
5351
DBModelProvider.HunYuan => new HunyuanChatService(model),
54-
DBModelProvider.Sparkdesk => new XunfeiChatService(model),
5552
DBModelProvider.LingYi => new LingYiChatService(model),
56-
DBModelProvider.DeepSeek => new DeepSeekChatService(model),
5753
DBModelProvider.xAI => new XAIChatService(model),
5854
DBModelProvider.GithubModels => new GithubModelsChatService(model),
5955
DBModelProvider.GoogleAI => new GoogleAI2ChatService(model),
60-
DBModelProvider.Ollama => new OllamaChatService(model),
61-
DBModelProvider.MiniMax => new MiniMaxChatService(model),
62-
DBModelProvider.Doubao => new DoubaoChatService(model),
6356
DBModelProvider.SiliconFlow => new SiliconFlowChatService(model),
6457
DBModelProvider.OpenRouter => new OpenRouterChatService(model, hostUrlService),
65-
_ => throw new NotSupportedException($"Unknown model provider: {modelProvider}")
58+
_ => new ChatCompletionService(model) // Fallback to OpenAI-compatible
6659
},
6760

6861
_ => throw new NotSupportedException($"Unknown API type: {apiType}")
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using Chats.BE.DB;
2+
using OpenAI;
3+
using OpenAI.Chat;
4+
using System.ClientModel.Primitives;
5+
6+
namespace Chats.BE.Services.Models.ChatServices.OpenAI;
7+
8+
public class AzureAIFoundryChatService(Model model) : ChatCompletionService(model, CreateAzureAIFoundryChatClient(model))
9+
{
10+
private static ChatClient CreateAzureAIFoundryChatClient(Model model)
11+
{
12+
OpenAIClient api = CreateOpenAIClient(model.ModelKey, []);
13+
return api.GetChatClient(model.DeploymentName);
14+
}
15+
16+
private new static OpenAIClient CreateOpenAIClient(ModelKey modelKey, PipelinePolicy[] perCallPolicies)
17+
{
18+
ModelKey transformedKey = CreateTransformedModelKey(modelKey);
19+
return ChatCompletionService.CreateOpenAIClient(transformedKey, perCallPolicies);
20+
}
21+
22+
internal static ModelKey CreateTransformedModelKey(ModelKey modelKey)
23+
{
24+
// 对于 Azure AI Foundry,先进行 Host 转换,确保 URL 以 /openai/v1/ 结尾
25+
string? transformedHost = TransformAzureAIFoundryHost(modelKey.Host)
26+
?? ModelProviderInfo.GetInitialHost((DB.Enums.DBModelProvider)modelKey.ModelProviderId);
27+
28+
// 创建一个新的 ModelKey 副本,使用转换后的 Host
29+
return new ModelKey()
30+
{
31+
Id = modelKey.Id,
32+
ModelProviderId = modelKey.ModelProviderId,
33+
Name = modelKey.Name,
34+
Host = transformedHost,
35+
Secret = modelKey.Secret,
36+
CreatedAt = modelKey.CreatedAt,
37+
UpdatedAt = modelKey.UpdatedAt,
38+
Order = modelKey.Order
39+
};
40+
}
41+
42+
internal static Uri? HostTransform(ModelKey key)
43+
{
44+
if (string.IsNullOrWhiteSpace(key.Host))
45+
{
46+
return null;
47+
}
48+
49+
string transformed = TransformAzureAIFoundryHost(key.Host) ?? key.Host;
50+
return new Uri(transformed);
51+
}
52+
53+
internal static string? TransformAzureAIFoundryHost(string? host)
54+
{
55+
if (string.IsNullOrWhiteSpace(host))
56+
{
57+
return null;
58+
}
59+
60+
// 如果已经以 /openai/v1 或 /openai/v1/ 结尾,不做修改
61+
if (host.EndsWith("/openai/v1") || host.EndsWith("/openai/v1/"))
62+
{
63+
return host;
64+
}
65+
66+
// 否则添加 /openai/v1/
67+
return host.TrimEnd('/') + "/openai/v1/";
68+
}
69+
}

src/BE/Services/Models/ChatServices/OpenAI/AzureChatCompletionService.cs

Lines changed: 0 additions & 22 deletions
This file was deleted.

src/BE/Services/Models/ChatServices/OpenAI/ChatCompletionService.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace Chats.BE.Services.Models.ChatServices.OpenAI;
1111

1212
public partial class ChatCompletionService(Model model, ChatClient chatClient) : ChatService(model)
1313
{
14-
public ChatCompletionService(Model model, Uri? suggestedApiUrl = null, params PipelinePolicy[] perCallPolicies) : this(model, CreateChatClient(model, suggestedApiUrl, perCallPolicies))
14+
public ChatCompletionService(Model model, params PipelinePolicy[] perCallPolicies) : this(model, CreateChatClient(model, perCallPolicies))
1515
{
1616
}
1717

@@ -23,18 +23,28 @@ public ChatCompletionService(Model model, Uri? suggestedApiUrl = null, params Pi
2323
"image/webp",
2424
];
2525

26-
private static ChatClient CreateChatClient(Model model, Uri? suggestedApiUrl, PipelinePolicy[] perCallPolicies)
26+
private static ChatClient CreateChatClient(Model model, PipelinePolicy[] perCallPolicies)
2727
{
28-
OpenAIClient api = CreateOpenAIClient(model.ModelKey, suggestedApiUrl, perCallPolicies);
28+
OpenAIClient api = CreateOpenAIClient(model.ModelKey, perCallPolicies);
2929
return api.GetChatClient(model.DeploymentName);
3030
}
3131

32-
internal static OpenAIClient CreateOpenAIClient(ModelKey modelKey, Uri? suggestedApiUrl, PipelinePolicy[] perCallPolicies)
32+
internal static OpenAIClient CreateOpenAIClient(ModelKey modelKey, PipelinePolicy[] perCallPolicies)
3333
{
3434
ArgumentException.ThrowIfNullOrWhiteSpace(modelKey.Secret, nameof(modelKey.Secret));
35+
36+
// Fallback logic: ModelKey.Host -> ModelProviderInfo.GetInitialHost
37+
Uri? endpoint = !string.IsNullOrWhiteSpace(modelKey.Host)
38+
? new Uri(modelKey.Host)
39+
: (ModelProviderInfo.GetInitialHost((DB.Enums.DBModelProvider)modelKey.ModelProviderId) switch
40+
{
41+
null => null,
42+
var x => new Uri(x)
43+
});
44+
3545
OpenAIClientOptions oaic = new()
3646
{
37-
Endpoint = !string.IsNullOrWhiteSpace(modelKey.Host) ? new Uri(modelKey.Host) : suggestedApiUrl,
47+
Endpoint = endpoint,
3848
NetworkTimeout = NetworkTimeout,
3949
RetryPolicy = new ClientRetryPolicy(maxRetries: 0),
4050
};

src/BE/Services/Models/ChatServices/OpenAI/DeepSeekChatService.cs

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/BE/Services/Models/ChatServices/OpenAI/DoubaoChatService.cs

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/BE/Services/Models/ChatServices/OpenAI/GLMChatService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace Chats.BE.Services.Models.ChatServices.OpenAI;
55

6-
public class GLMChatService(Model model) : ChatCompletionService(model, new Uri("https://open.bigmodel.cn/api/paas/v4/"))
6+
public class GLMChatService(Model model) : ChatCompletionService(model)
77
{
88
protected override void SetWebSearchEnabled(ChatCompletionOptions options, bool enabled)
99
{

src/BE/Services/Models/ChatServices/OpenAI/GithubModelsChatService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Chats.BE.Services.Models.ChatServices.OpenAI;
66

7-
public class GithubModelsChatService(Model model) : ChatCompletionService(model, new Uri("https://models.inference.ai.azure.com"))
7+
public class GithubModelsChatService(Model model) : ChatCompletionService(model)
88
{
99
protected override Task<ChatMessage[]> FEPreprocess(IReadOnlyList<ChatMessage> messages, ChatCompletionOptions options, ChatExtraDetails feOptions, FileUrlProvider fup, CancellationToken cancellationToken)
1010
{

0 commit comments

Comments
 (0)