diff --git a/.github/workflows/build-container.yml b/.github/workflows/build-container.yml
index e61cd983..b02f3180 100644
--- a/.github/workflows/build-container.yml
+++ b/.github/workflows/build-container.yml
@@ -97,6 +97,12 @@ jobs:
name: chats-fe
path: ./src/BE/wwwroot
+ - name: sed version
+ run: |
+ # file: ./src/BE/Controllers/Admin/GlobalConfigs/VersionController.cs
+ # const int buildVersion = 0; -> const int buildVersion = github.run_number;
+ sed -i "s/const int buildVersion = 0;/const int buildVersion = ${{ github.run_number }};/" ./src/BE/Controllers/Admin/GlobalConfigs/VersionController.cs
+
- name: Build container
run: |
dotnet publish ./src/BE/Chats.BE.csproj -c Release --os linux --arch x64 /t:PublishContainer /p:ContainerRepository=chats
@@ -143,6 +149,12 @@ jobs:
name: chats-fe
path: ./src/BE/wwwroot
+ - name: sed version
+ run: |
+ # file: ./src/BE/Controllers/Admin/GlobalConfigs/VersionController.cs
+ # const int buildVersion = 0; -> const int buildVersion = github.run_number;
+ sed -i "s/const int buildVersion = 0;/const int buildVersion = ${{ github.run_number }};/" ./src/BE/Controllers/Admin/GlobalConfigs/VersionController.cs
+
- name: Build container
run: |
dotnet publish ./src/BE/Chats.BE.csproj -c Release --os ${{ matrix.os }} --arch ${{ matrix.arch }} /t:PublishContainer /p:ContainerRepository=chats ${{ matrix.args }}
@@ -228,6 +240,12 @@ jobs:
name: chats-fe
path: ./src/BE/wwwroot
+ - name: sed version
+ run: |
+ # file: ./src/BE/Controllers/Admin/GlobalConfigs/VersionController.cs
+ # const int buildVersion = 0; -> const int buildVersion = github.run_number;
+ sed -i "s/const int buildVersion = 0;/const int buildVersion = ${{ github.run_number }};/" ./src/BE/Controllers/Admin/GlobalConfigs/VersionController.cs
+
- name: build binary
run: |
dotnet publish ./src/BE/Chats.BE.csproj -c Release -o ./Publish ${{ matrix.args }} /p:DeleteExistingFiles=True
@@ -291,6 +309,8 @@ jobs:
target_commitish: '${{ github.sha }}',
body: `### Full Changelogs
https://github.com/sdcb/chats/compare/${latestTag}...r-${{ github.run_number }}
+
+
### Docker
| Description | Docker Image |
@@ -317,6 +337,8 @@ jobs:
**NOTE**:
Replace \`r${{ github.run_number }}\` with \`latest\` in the download link to get the latest version, for example: \`${{ vars.MINIO_URL }}/chats/latest/chats-win-x64.7z\`
+
+
`,
draft: false,
prerelease: false,
diff --git a/README.md b/README.md
index 04ab3725..b9f7b24b 100644
--- a/README.md
+++ b/README.md
@@ -132,8 +132,9 @@ C:\Users\ZhouJie\Downloads\chats-win-x64>dir
- **启动应用**:运行 `Chats.BE.exe` 即可启动 Chats 应用,该文件名虽指“后端”,但实际同时包含前端和后端组件。
- **数据库配置**:默认情况下,应用将在当前目录创建名为 `AppData` 的目录,并以 SQLite 作为数据库。命令行参数可用于指定不同的数据库类型:
```pwsh
- .\Chats.BE.exe --DBType=mssql --ConnectionStrings:ChatsDB="Data Source=(localdb)\mssqllocaldb; Initial Catalog=ChatsDB; Integrated Security=True"
+ .\Chats.BE.exe --urls http://+:5000 --DBType=mssql --ConnectionStrings:ChatsDB="Data Source=(localdb)\mssqllocaldb; Initial Catalog=ChatsDB; Integrated Security=True"
```
+ - 参数 `--urls`:用于指定应用监听的地址和端口。
- 参数 `DBType`:可选 `sqlite`、`mssql` 或 `pgsql`。
- 参数 `--ConnectionStrings:ChatsDB`:用于指定数据库的ADO.NET连接字符串。
diff --git a/README_EN.md b/README_EN.md
index 363278e5..5eb923fd 100644
--- a/README_EN.md
+++ b/README_EN.md
@@ -130,8 +130,9 @@ C:\Users\ZhouJie\Downloads\chats-win-x64>dir
- **Start Application**: Run `Chats.BE.exe` to start the Chats application. Although this filename indicates "backend," it actually contains both frontend and backend components.
- **Database Configuration**: By default, the application will create a directory named `AppData` in the current directory and use SQLite as the database. Command-line parameters can be used to specify a different database type:
```pwsh
- .\Chats.BE.exe --DBType=mssql --ConnectionStrings:ChatsDB="Data Source=(localdb)\mssqllocaldb; Initial Catalog=ChatsDB; Integrated Security=True"
+ .\Chats.BE.exe --urls http://+:5000 --DBType=mssql --ConnectionStrings:ChatsDB="Data Source=(localdb)\mssqllocaldb; Initial Catalog=ChatsDB; Integrated Security=True"
```
+ - Parameter `--urls`: Used to specify the address and port the application listens on.
- Parameter `DBType`: Options are `sqlite`, `mssql`, or `pgsql`.
- Parameter `--ConnectionStrings:ChatsDB`: For specifying the ADO.NET connection string for the database.
diff --git a/src/BE.Tests/Services/Conversations/ChatCompletionOptionsTests.cs b/src/BE.Tests/Services/Conversations/ChatCompletionOptionsTests.cs
index 2a2ad9fc..a44f5ea7 100644
--- a/src/BE.Tests/Services/Conversations/ChatCompletionOptionsTests.cs
+++ b/src/BE.Tests/Services/Conversations/ChatCompletionOptionsTests.cs
@@ -1,4 +1,4 @@
-using Chats.BE.Services.ChatServices.Extensions;
+using Chats.BE.Services.Models.Extensions;
using OpenAI.Chat;
using System.Runtime.CompilerServices;
diff --git a/src/BE/Chats.BE.csproj b/src/BE/Chats.BE.csproj
index 6958fba4..b8f06b4d 100644
--- a/src/BE/Chats.BE.csproj
+++ b/src/BE/Chats.BE.csproj
@@ -9,11 +9,11 @@
-
+
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -22,16 +22,16 @@
-
+
-
+
-
-
+
+
diff --git a/src/BE/Controllers/Admin/AdminMessage/AdminMessageController.cs b/src/BE/Controllers/Admin/AdminMessage/AdminMessageController.cs
index 5f829825..d66436b5 100644
--- a/src/BE/Controllers/Admin/AdminMessage/AdminMessageController.cs
+++ b/src/BE/Controllers/Admin/AdminMessage/AdminMessageController.cs
@@ -5,7 +5,7 @@
using Chats.BE.Controllers.Common.Dtos;
using Chats.BE.DB;
using Chats.BE.Infrastructure;
-using Chats.BE.Services.ChatServices;
+using Chats.BE.Services.Models;
using Chats.BE.Services.FileServices;
using Chats.BE.Services.UrlEncryption;
using Microsoft.AspNetCore.Mvc;
@@ -100,6 +100,7 @@ public async Task> GetAdminMessage(int ch
.ToArray(),
CreatedAt = x.CreatedAt,
SpanId = x.SpanId,
+ Edited = x.Edited,
Usage = x.Usage == null ? null : new ChatMessageTempUsage()
{
InputTokens = x.Usage.InputTokens,
diff --git a/src/BE/Controllers/Admin/AdminModels/AdminModelsController.cs b/src/BE/Controllers/Admin/AdminModels/AdminModelsController.cs
index 5081b438..e3d289db 100644
--- a/src/BE/Controllers/Admin/AdminModels/AdminModelsController.cs
+++ b/src/BE/Controllers/Admin/AdminModels/AdminModelsController.cs
@@ -5,7 +5,7 @@
using Chats.BE.DB.Jsons;
using Chats.BE.Infrastructure;
using Chats.BE.Services;
-using Chats.BE.Services.ChatServices;
+using Chats.BE.Services.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.EntityFrameworkCore;
@@ -122,13 +122,6 @@ public async Task> FastCreateModel([FromBody] ValidateModelReq
return BadRequest($"Invalid ModelReferenceId: {req.ModelReferenceId}");
}
- bool hasExistingModel = await db.Models
- .AnyAsync(x => x.ModelKeyId == req.ModelKeyId && x.ModelReferenceId == req.ModelReferenceId && x.DeploymentName == req.DeploymentName, cancellationToken);
- if (hasExistingModel)
- {
- return BadRequest("Model already exists");
- }
-
Model toCreate = new()
{
ModelKeyId = req.ModelKeyId,
@@ -182,7 +175,7 @@ public async Task DeleteModel(short modelId, CancellationToken can
[HttpPost("models/validate")]
public async Task> ValidateModel(
[FromBody] ValidateModelRequest req,
- [FromServices] ChatFactory conversationFactory,
+ [FromServices] ChatFactory chatFactory,
CancellationToken cancellationToken)
{
ModelKey? modelKey = await db.ModelKeys
@@ -204,12 +197,12 @@ public async Task> ValidateModel(
return this.BadRequestMessage($"Model reference id: {req.ModelReferenceId} not found");
}
- ModelValidateResult result = await conversationFactory.ValidateModel(modelKey, modelReference, req.DeploymentName, cancellationToken);
+ ModelValidateResult result = await chatFactory.ValidateModel(modelKey, modelReference, req.DeploymentName, cancellationToken);
return Ok(result);
}
[HttpGet("user-models/{userId:int}")]
- public async Task>> GetUserModels(int userId, CancellationToken cancellationToken)
+ public async Task> GetUserModels(int userId, CancellationToken cancellationToken)
{
UserModelDto[] userModels = await db.Models
.Where(x => !x.IsDeleted)
diff --git a/src/BE/Controllers/Admin/GlobalConfigs/GlobalConfigController.cs b/src/BE/Controllers/Admin/GlobalConfigs/GlobalConfigController.cs
index 453eb99f..b09da0a5 100644
--- a/src/BE/Controllers/Admin/GlobalConfigs/GlobalConfigController.cs
+++ b/src/BE/Controllers/Admin/GlobalConfigs/GlobalConfigController.cs
@@ -2,6 +2,7 @@
using Chats.BE.Controllers.Admin.GlobalConfigs.Dtos;
using Chats.BE.Controllers.Common;
using Chats.BE.DB;
+using Chats.BE.Services.Configs;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Text.Json;
diff --git a/src/BE/Controllers/Admin/GlobalConfigs/VersionController.cs b/src/BE/Controllers/Admin/GlobalConfigs/VersionController.cs
index 361000a1..12f169ee 100644
--- a/src/BE/Controllers/Admin/GlobalConfigs/VersionController.cs
+++ b/src/BE/Controllers/Admin/GlobalConfigs/VersionController.cs
@@ -7,16 +7,17 @@ namespace Chats.BE.Controllers.Admin.GlobalConfigs;
[AuthorizeAdmin, Route("api/version")]
public class VersionController : ControllerBase
{
+ // it will be replaced by CI/CD pipeline
const int buildVersion = 0;
- [HttpGet("current")]
- public ActionResult GetCurrentVersion()
+ [HttpGet]
+ public ActionResult GetCurrentVersion()
{
return Ok(buildVersion);
}
[HttpPost("check-update")]
- public async Task CheckUpdate(CancellationToken cancellationToken)
+ public async Task> CheckUpdate(CancellationToken cancellationToken)
{
string tagName = await GitHubReleaseChecker.SdcbChats.GetLatestReleaseTagNameAsync(cancellationToken);
bool hasNewVersion = GitHubReleaseChecker.IsNewVersionAvailableAsync(tagName, buildVersion);
diff --git a/src/BE/Controllers/Admin/ModelKeys/Dtos/AutoCreateModelResult.cs b/src/BE/Controllers/Admin/ModelKeys/Dtos/AutoCreateModelResult.cs
index 9e976dbc..619920f6 100644
--- a/src/BE/Controllers/Admin/ModelKeys/Dtos/AutoCreateModelResult.cs
+++ b/src/BE/Controllers/Admin/ModelKeys/Dtos/AutoCreateModelResult.cs
@@ -1,5 +1,5 @@
using Chats.BE.DB;
-using Chats.BE.Services.ChatServices;
+using Chats.BE.Services.Models;
using System.Text.Json.Serialization;
namespace Chats.BE.Controllers.Admin.ModelKeys.Dtos;
diff --git a/src/BE/Controllers/Admin/ModelKeys/ModelKeysController.cs b/src/BE/Controllers/Admin/ModelKeys/ModelKeysController.cs
index 8a01c9cb..0b3905e9 100644
--- a/src/BE/Controllers/Admin/ModelKeys/ModelKeysController.cs
+++ b/src/BE/Controllers/Admin/ModelKeys/ModelKeysController.cs
@@ -2,8 +2,9 @@
using Chats.BE.Controllers.Admin.ModelKeys.Dtos;
using Chats.BE.Controllers.Common;
using Chats.BE.DB;
+using Chats.BE.DB.Enums;
using Chats.BE.Services.Common;
-using Chats.BE.Services.ChatServices;
+using Chats.BE.Services.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
@@ -114,75 +115,8 @@ public async Task DeleteModelKey(short modelKeyId, CancellationTok
return NoContent();
}
- [HttpPost("{modelKeyId:int}/auto-create-models")]
- public async Task> AutoCreateModels(short modelKeyId, [FromServices] ChatFactory conversationFactory, CancellationToken cancellationToken)
- {
- ModelKey? modelKey = await db
- .ModelKeys
- .Include(x => x.Models)
- .AsSplitQuery()
- .FirstOrDefaultAsync(x => x.Id == modelKeyId, cancellationToken);
-
- if (modelKey == null)
- {
- return NotFound();
- }
-
- HashSet existingModelRefIds = modelKey.Models
- .Select(x => x.ModelReferenceId)
- .ToHashSet();
-
- ModelReference[] readyRefs = await db.ModelReferences
- .Include(x => x.CurrencyCodeNavigation)
- .Where(x => !x.IsLegacy && x.ProviderId == modelKey.ModelProviderId)
- .ToArrayAsync(cancellationToken);
-
- ParepareAutoCreateModelResult[] scanedModels = await Task.WhenAll(readyRefs
- .Select(async r => existingModelRefIds.Contains(r.Id)
- ? ParepareAutoCreateModelResult.ModelAlreadyExists(r)
- : ParepareAutoCreateModelResult.FromModelValidateResult(await conversationFactory.ValidateModel(modelKey, r, r.Name, cancellationToken), r)));
-
- FileService? fileService = await db.FileServices
- .OrderByDescending(x => x.Id)
- .FirstOrDefaultAsync(cancellationToken);
- AutoCreateModelResult[] results = await scanedModels
- .ToAsyncEnumerable()
- .SelectAwait(async (m) =>
- {
- if (!m.IsValidationPassed)
- {
- return m.ToResult(null);
- }
-
- db.Models.Add(new Model
- {
- ModelKeyId = modelKeyId,
- ModelReferenceId = m.ModelReference.Id,
- Name = m.ModelReference.Name,
- CreatedAt = DateTime.UtcNow,
- UpdatedAt = DateTime.UtcNow,
- DeploymentName = null, // don't need to specify deploymentName because it's auto created
- IsDeleted = false,
- InputTokenPrice1M = m.ModelReference.InputTokenPrice1M * m.ModelReference.CurrencyCodeNavigation.ExchangeRate,
- OutputTokenPrice1M = m.ModelReference.OutputTokenPrice1M * m.ModelReference.CurrencyCodeNavigation.ExchangeRate,
- });
- try
- {
- await db.SaveChangesAsync(cancellationToken);
- return m.ToResult(null);
- }
- catch (Exception ex)
- {
- return m.ToResult(ex.Message);
- }
- })
- .ToArrayAsync(cancellationToken);
-
- return Ok(results);
- }
-
[HttpGet("{modelKeyId:int}/possible-models")]
- public async Task> ListModelKeyPossibleModels(short modelKeyId, CancellationToken cancellationToken)
+ public async Task> ListModelKeyPossibleModels(short modelKeyId, [FromServices] ChatFactory cf, CancellationToken cancellationToken)
{
ModelKey? modelKey = await db
.ModelKeys
@@ -195,21 +129,77 @@ public async Task> ListModelKeyPossibleModels(s
return NotFound();
}
- PossibleModelDto[] readyRefs = await db.ModelReferences
- .Where(x => x.ProviderId == modelKey.ModelProviderId)
- .OrderBy(x => x.Name)
- .Select(x => new PossibleModelDto()
+ DBModelProvider modelProvider = (DBModelProvider)modelKey.ModelProviderId;
+ ModelLoader? loader = cf.CreateModelLoader(modelProvider);
+ if (loader != null)
+ {
+ string[] models = await loader.ListModels(modelKey, cancellationToken);
+ HashSet existsDeploymentNames = await db.Models
+ .Where(x => x.ModelKeyId == modelKeyId && x.DeploymentName != null)
+ .Select(x => x.DeploymentName!)
+ .ToHashSetAsync(cancellationToken);
+
+ if (modelProvider == DBModelProvider.Ollama)
{
- DeploymentName = x.Models.FirstOrDefault(m => m.ModelKeyId == modelKeyId)!.DeploymentName,
- ReferenceId = x.Id,
- ReferenceName = x.Name,
- IsLegacy = x.IsLegacy,
- IsExists = x.Models.Any(m => m.ModelKeyId == modelKeyId),
- })
- .OrderBy(x => (x.IsLegacy ? 1 : 0) + (x.IsExists ? 2 : 0))
- .ThenByDescending(x => x.ReferenceId)
- .ToArrayAsync(cancellationToken);
+ Dictionary referenceOptions = await db.ModelReferences
+ .Where(x => x.ProviderId == modelKey.ModelProviderId)
+ .ToDictionaryAsync(k => k.Id, v => v, cancellationToken);
- return Ok(readyRefs);
+ return Ok(models.Select(model =>
+ {
+ bool isVision = model.Contains("qvq", StringComparison.OrdinalIgnoreCase) ||
+ model.Contains("vision", StringComparison.OrdinalIgnoreCase);
+ short modelReferenceId = isVision ? (short)1401 : (short)1400;
+ return new PossibleModelDto()
+ {
+ DeploymentName = model,
+ ReferenceId = modelReferenceId,
+ ReferenceName = referenceOptions[modelReferenceId].Name,
+ IsLegacy = referenceOptions[modelReferenceId].IsLegacy,
+ IsExists = existsDeploymentNames.Contains(model),
+ };
+ }));
+ }
+ else
+ {
+ Dictionary referenceOptions = await db.ModelReferences
+ .Where(x => x.ProviderId == modelKey.ModelProviderId)
+ .ToDictionaryAsync(k => k.Name, v => v, cancellationToken);
+ HashSet referenceOptionNames = [.. referenceOptions.Keys];
+
+ return Ok(models.Select(model =>
+ {
+ string bestMatch = FuzzyMatcher.FindBestMatch(model, referenceOptionNames);
+
+ return new PossibleModelDto()
+ {
+ DeploymentName = model,
+ ReferenceId = referenceOptions[bestMatch].Id,
+ ReferenceName = referenceOptions[bestMatch].Name,
+ IsLegacy = false,
+ IsExists = existsDeploymentNames.Contains(model),
+ };
+ }).ToArray());
+ }
+ }
+ else
+ {
+ PossibleModelDto[] readyRefs = await db.ModelReferences
+ .Where(x => x.ProviderId == modelKey.ModelProviderId)
+ .OrderBy(x => x.Name)
+ .Select(x => new PossibleModelDto()
+ {
+ DeploymentName = x.Models.FirstOrDefault(m => m.ModelKeyId == modelKeyId)!.DeploymentName,
+ ReferenceId = x.Id,
+ ReferenceName = x.Name,
+ IsLegacy = x.IsLegacy,
+ IsExists = x.Models.Any(m => m.ModelKeyId == modelKeyId),
+ })
+ .OrderBy(x => (x.IsLegacy ? 1 : 0) + (x.IsExists ? 2 : 0))
+ .ThenByDescending(x => x.ReferenceId)
+ .ToArrayAsync(cancellationToken);
+
+ return Ok(readyRefs);
+ }
}
}
diff --git a/src/BE/Controllers/Chats/Chats/ChatController.cs b/src/BE/Controllers/Chats/Chats/ChatController.cs
index 43f6f3b0..279a318d 100644
--- a/src/BE/Controllers/Chats/Chats/ChatController.cs
+++ b/src/BE/Controllers/Chats/Chats/ChatController.cs
@@ -2,9 +2,9 @@
using Chats.BE.DB;
using Chats.BE.Infrastructure;
using Chats.BE.Services;
-using Chats.BE.Services.ChatServices;
-using Chats.BE.Services.ChatServices.Dtos;
-using Chats.BE.Services.ChatServices.Implementations.Test;
+using Chats.BE.Services.Models;
+using Chats.BE.Services.Models.Dtos;
+using Chats.BE.Services.Models.ChatServices.Test;
using Chats.BE.Services.FileServices;
using Chats.BE.Services.UrlEncryption;
using Microsoft.AspNetCore.Authorization;
@@ -399,7 +399,7 @@ private static async Task ProcessChatSpan(
string? errorText = null;
try
{
- using ChatService s = chatFactory.CreateConversationService(userModel.Model);
+ using ChatService s = chatFactory.CreateChatService(userModel.Model);
await foreach (InternalChatSegment seg in icc.Run(userBalance.Balance, userModel, s.ChatStreamedFEProcessed(messageToSend, cco, extraDetails, cancellationToken)))
{
if (seg.TextSegment == string.Empty) continue;
diff --git a/src/BE/Controllers/Chats/Chats/Dtos/ChatRequest.cs b/src/BE/Controllers/Chats/Chats/Dtos/ChatRequest.cs
index 491cf2dd..1ac45113 100644
--- a/src/BE/Controllers/Chats/Chats/Dtos/ChatRequest.cs
+++ b/src/BE/Controllers/Chats/Chats/Dtos/ChatRequest.cs
@@ -1,6 +1,6 @@
using Chats.BE.Controllers.Chats.Messages.Dtos;
using Chats.BE.DB;
-using Chats.BE.Services.ChatServices.Extensions;
+using Chats.BE.Services.Models.Extensions;
using OpenAI.Chat;
using System.Text.Json.Serialization;
diff --git a/src/BE/Controllers/Chats/Chats/Dtos/MessageLiteDto.cs b/src/BE/Controllers/Chats/Chats/Dtos/MessageLiteDto.cs
index 5acbc5b6..899fd3ad 100644
--- a/src/BE/Controllers/Chats/Chats/Dtos/MessageLiteDto.cs
+++ b/src/BE/Controllers/Chats/Chats/Dtos/MessageLiteDto.cs
@@ -1,6 +1,6 @@
using Chats.BE.DB;
using Chats.BE.DB.Enums;
-using Chats.BE.Services.ChatServices;
+using Chats.BE.Services.Models;
using Chats.BE.Services.FileServices;
using OpenAI.Chat;
diff --git a/src/BE/Controllers/Chats/Chats/Dtos/SseResponseLine.cs b/src/BE/Controllers/Chats/Chats/Dtos/SseResponseLine.cs
index a781fe89..edffeb0a 100644
--- a/src/BE/Controllers/Chats/Chats/Dtos/SseResponseLine.cs
+++ b/src/BE/Controllers/Chats/Chats/Dtos/SseResponseLine.cs
@@ -1,6 +1,6 @@
using Chats.BE.Controllers.Chats.Messages.Dtos;
using Chats.BE.DB;
-using Chats.BE.Services.ChatServices;
+using Chats.BE.Services.Models;
using Chats.BE.Services.FileServices;
using Chats.BE.Services.UrlEncryption;
using System.Text.Json.Serialization;
@@ -52,6 +52,7 @@ public static SseResponseLine ResponseMessage(
ParentId = assistantMessage.ParentId,
Role = (DBChatRole)assistantMessage.ChatRoleId,
SpanId = assistantMessage.SpanId,
+ Edited = assistantMessage.Edited,
Usage = assistantMessage.Usage == null ? null : new ChatMessageTempUsage()
{
Duration = assistantMessage.Usage.TotalDurationMs - assistantMessage.Usage.PreprocessDurationMs,
@@ -89,6 +90,7 @@ public static SseResponseLine UserMessage(
ParentId = userMessage.ParentId,
Role = (DBChatRole)userMessage.ChatRoleId,
SpanId = userMessage.SpanId,
+ Edited = userMessage.Edited,
Usage = null,
};
MessageDto userMessageDto = userMessageTemp.ToDto(urlEncryptionService, fup);
diff --git a/src/BE/Controllers/Chats/Chats/InsufficientBalanceException.cs b/src/BE/Controllers/Chats/Chats/InsufficientBalanceException.cs
index 728e6cbb..ad65abcf 100644
--- a/src/BE/Controllers/Chats/Chats/InsufficientBalanceException.cs
+++ b/src/BE/Controllers/Chats/Chats/InsufficientBalanceException.cs
@@ -1,4 +1,4 @@
-using Chats.BE.Services.ChatServices;
+using Chats.BE.Services.Models;
namespace Chats.BE.Controllers.Chats.Chats;
diff --git a/src/BE/Controllers/Chats/Messages/Dtos/MessageDto.cs b/src/BE/Controllers/Chats/Messages/Dtos/MessageDto.cs
index 6d4748e8..eeea197d 100644
--- a/src/BE/Controllers/Chats/Messages/Dtos/MessageDto.cs
+++ b/src/BE/Controllers/Chats/Messages/Dtos/MessageDto.cs
@@ -1,6 +1,6 @@
using Chats.BE.DB;
using Chats.BE.DB.Enums;
-using Chats.BE.Services.ChatServices;
+using Chats.BE.Services.Models;
using Chats.BE.Services.FileServices;
using Chats.BE.Services.UrlEncryption;
using System.Text.Json.Serialization;
@@ -29,9 +29,27 @@ public abstract record MessageDto
[JsonPropertyName("spanId")]
public required byte? SpanId { get; init; }
+
+ [JsonPropertyName("edited")]
+ public required bool Edited { get; init; }
}
-public record RequestMessageDto : MessageDto;
+public record RequestMessageDto : MessageDto
+{
+ public static RequestMessageDto FromDB(Message message, FileUrlProvider fup)
+ {
+ return new RequestMessageDto()
+ {
+ Id = message.Id.ToString(),
+ ParentId = message.ParentId?.ToString(),
+ Role = (DBChatRole)message.ChatRoleId,
+ Content = MessageContentResponse.FromSegments([.. message.MessageContents], fup),
+ CreatedAt = message.CreatedAt,
+ SpanId = message.SpanId,
+ Edited = message.Edited,
+ };
+ }
+}
public record ResponseMessageDto : MessageDto
{
@@ -128,8 +146,10 @@ public static MessageContentResponse FromSegments(MessageContent[] segments, Fil
public record FileDto
{
+ [JsonPropertyName("id")]
public required string Id { get; init; }
+ [JsonPropertyName("url")]
public required Uri Url { get; init; }
}
@@ -157,6 +177,7 @@ public record ChatMessageTemp
public required MessageContent[] Content { get; init; }
public required DateTime CreatedAt { get; init; }
public required byte? SpanId { get; init; }
+ public required bool Edited { get; init; }
public required ChatMessageTempUsage? Usage { get; init; }
public MessageDto ToDto(IUrlEncryptionService urlEncryption, FileUrlProvider fup)
@@ -171,6 +192,7 @@ public MessageDto ToDto(IUrlEncryptionService urlEncryption, FileUrlProvider fup
Content = MessageContentResponse.FromSegments(Content, fup),
CreatedAt = CreatedAt,
SpanId = SpanId,
+ Edited = Edited,
};
}
else
@@ -183,6 +205,7 @@ public MessageDto ToDto(IUrlEncryptionService urlEncryption, FileUrlProvider fup
Content = MessageContentResponse.FromSegments(Content, fup),
CreatedAt = CreatedAt,
SpanId = SpanId,
+ Edited = Edited,
InputTokens = Usage.InputTokens,
OutputTokens = Usage.OutputTokens,
diff --git a/src/BE/Controllers/Chats/Messages/MessagesController.cs b/src/BE/Controllers/Chats/Messages/MessagesController.cs
index 27fcea1c..95232933 100644
--- a/src/BE/Controllers/Chats/Messages/MessagesController.cs
+++ b/src/BE/Controllers/Chats/Messages/MessagesController.cs
@@ -2,7 +2,7 @@
using Chats.BE.DB;
using Chats.BE.DB.Enums;
using Chats.BE.Infrastructure;
-using Chats.BE.Services.ChatServices;
+using Chats.BE.Services.Models;
using Chats.BE.Services.FileServices;
using Chats.BE.Services.UrlEncryption;
using Microsoft.AspNetCore.Authorization;
@@ -32,6 +32,7 @@ public async Task> GetMessages(string chatId, [FromSe
.ToArray(),
CreatedAt = x.CreatedAt,
SpanId = x.SpanId,
+ Edited = x.Edited,
Usage = x.Usage == null ? null : new ChatMessageTempUsage()
{
InputTokens = x.Usage.InputTokens,
@@ -112,8 +113,8 @@ private async Task ReactionPrivate(string encryptedMessageId, bool
return Ok();
}
- [HttpPut("{encryptedMessageId}/edit")]
- public async Task EditMessage(string encryptedMessageId, [FromBody] MessageContentRequest content,
+ [HttpPut("{encryptedMessageId}/edit-in-place")]
+ public async Task EditMessageInPlace(string encryptedMessageId, [FromBody] MessageContentRequest content,
[FromServices] FileUrlProvider fup,
CancellationToken cancellationToken)
{
@@ -131,14 +132,19 @@ public async Task EditMessage(string encryptedMessageId, [FromBody
return Forbid();
}
- message.MessageContents = await content.ToMessageContents(fup, cancellationToken);
+ message.MessageContents.Clear();
+ foreach (MessageContent c in await content.ToMessageContents(fup, cancellationToken))
+ {
+ message.MessageContents.Add(c);
+ }
message.Chat.UpdatedAt = DateTime.UtcNow;
+ message.Edited = true;
await db.SaveChangesAsync(cancellationToken);
return Ok();
}
[HttpPut("{encryptedMessageId}/edit-and-save-new")]
- public async Task EditAndSaveNew(string encryptedMessageId, [FromBody] MessageContentRequest content,
+ public async Task> EditAndSaveNew(string encryptedMessageId, [FromBody] MessageContentRequest content,
[FromServices] FileUrlProvider fup,
CancellationToken cancellationToken)
{
@@ -170,7 +176,7 @@ public async Task EditAndSaveNew(string encryptedMessageId, [FromB
db.Messages.Add(newMessage);
message.Chat.UpdatedAt = DateTime.UtcNow;
await db.SaveChangesAsync(cancellationToken);
- return Ok();
+ return Ok(RequestMessageDto.FromDB(newMessage, fup));
}
[HttpDelete("{encryptedMessageId}")]
diff --git a/src/BE/Controllers/Chats/Prompts/PromptsController.cs b/src/BE/Controllers/Chats/Prompts/PromptsController.cs
index 498f0b0e..c9dee318 100644
--- a/src/BE/Controllers/Chats/Prompts/PromptsController.cs
+++ b/src/BE/Controllers/Chats/Prompts/PromptsController.cs
@@ -1,7 +1,7 @@
using Chats.BE.Controllers.Chats.Prompts.Dtos;
using Chats.BE.DB;
using Chats.BE.Infrastructure;
-using Chats.BE.Services.ChatServices;
+using Chats.BE.Services.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
diff --git a/src/BE/Controllers/Chats/UserChats/UserChatsController.cs b/src/BE/Controllers/Chats/UserChats/UserChatsController.cs
index 22113e67..34b985cd 100644
--- a/src/BE/Controllers/Chats/UserChats/UserChatsController.cs
+++ b/src/BE/Controllers/Chats/UserChats/UserChatsController.cs
@@ -4,7 +4,7 @@
using Chats.BE.DB;
using Chats.BE.Infrastructure;
using Chats.BE.Services;
-using Chats.BE.Services.ChatServices;
+using Chats.BE.Services.Models;
using Chats.BE.Services.UrlEncryption;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
diff --git a/src/BE/Controllers/OpenAICompatible/OpenAICompatibleController.cs b/src/BE/Controllers/OpenAICompatible/OpenAICompatibleController.cs
index 3f57a8c4..4e46e035 100644
--- a/src/BE/Controllers/OpenAICompatible/OpenAICompatibleController.cs
+++ b/src/BE/Controllers/OpenAICompatible/OpenAICompatibleController.cs
@@ -1,8 +1,8 @@
using Chats.BE.Controllers.Chats.Chats;
using Chats.BE.DB;
using Chats.BE.Services;
-using Chats.BE.Services.ChatServices;
-using Chats.BE.Services.ChatServices.Dtos;
+using Chats.BE.Services.Models;
+using Chats.BE.Services.Models.Dtos;
using Chats.BE.Services.OpenAIApiKeySession;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@@ -37,7 +37,7 @@ public async Task ChatCompletion([FromBody] JsonObject json, [From
if (userModel == null) return InvalidModel(cco.Model);
Model cm = userModel.Model;
- using ChatService s = cf.CreateConversationService(cm);
+ using ChatService s = cf.CreateChatService(cm);
UserBalance userBalance = await db.UserBalances
.Where(x => x.UserId == currentApiKey.User.Id)
diff --git a/src/BE/DB/ChatsDB.cs b/src/BE/DB/ChatsDB.cs
index 0ab8b5f9..06a506fa 100644
--- a/src/BE/DB/ChatsDB.cs
+++ b/src/BE/DB/ChatsDB.cs
@@ -158,9 +158,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity(entity =>
{
- entity.HasOne(d => d.Chat).WithMany(p => p.ChatShares)
- .OnDelete(DeleteBehavior.ClientSetNull)
- .HasConstraintName("FK_ChatShare_Chat");
+ entity.HasOne(d => d.Chat).WithMany(p => p.ChatShares).HasConstraintName("FK_ChatShare_Chat");
});
modelBuilder.Entity(entity =>
diff --git a/src/BE/DB/Design/CustomDesignTimeServices.cs b/src/BE/DB/Design/CustomDesignTimeServices.cs
deleted file mode 100644
index 61c53ef3..00000000
--- a/src/BE/DB/Design/CustomDesignTimeServices.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using Microsoft.EntityFrameworkCore.Design;
-
-namespace Chats.BE.DB.Design;
-
-public class CustomDesignTimeServices : IDesignTimeServices
-{
- public void ConfigureDesignTimeServices(IServiceCollection services)
- {
- }
-}
\ No newline at end of file
diff --git a/src/BE/DB/Enums/DBModelProvider.cs b/src/BE/DB/Enums/DBModelProvider.cs
index af64bcff..173336c4 100644
--- a/src/BE/DB/Enums/DBModelProvider.cs
+++ b/src/BE/DB/Enums/DBModelProvider.cs
@@ -16,4 +16,6 @@ public enum DBModelProvider
xAI = 11,
GithubModels = 12,
GoogleAI = 13,
+ Ollama = 14,
+ MiniMax = 15,
}
diff --git a/src/BE/DB/Init/BasicData.cs b/src/BE/DB/Init/BasicData.cs
index b62b4bb3..45baad70 100644
--- a/src/BE/DB/Init/BasicData.cs
+++ b/src/BE/DB/Init/BasicData.cs
@@ -107,7 +107,7 @@ private static void InsertTransactionTypes(ChatsDB db)
private static void InsertModelReferences(ChatsDB db)
{
- // Generated from data, hash: 9a260fb4f9f10c860ddfa1eba88bb4f3097caddf475eb39618431604002b38aa
+ // Generated from data, hash: 88ff31dc432a7309dd0e65065384a0d87443fca7838456ac41c2d179bcbfa93c
db.ModelReferences.AddRange(
[
new(){ Id=0, ProviderId=0, Name="Test", ShortName=null, IsLegacy=false, MinTemperature=0.00M, MaxTemperature=2.00M, AllowSearch=false, AllowVision=true, AllowSystemPrompt=true, AllowStreaming=true, ContextWindow=2048, MaxResponseTokens=2048, TokenizerId=1, InputTokenPrice1M=0.00000M, OutputTokenPrice1M=0.00000M, CurrencyCode="RMB", },
@@ -248,13 +248,19 @@ private static void InsertModelReferences(ChatsDB db)
new(){ Id=1217, ProviderId=12, Name="Phi-3.5-vision-instruct", ShortName="Phi-3.5", IsLegacy=false, MinTemperature=0.00M, MaxTemperature=2.00M, AllowSearch=false, AllowVision=true, AllowSystemPrompt=true, AllowStreaming=true, ContextWindow=131072, MaxResponseTokens=4096, TokenizerId=null, InputTokenPrice1M=1.00000M, OutputTokenPrice1M=2.00000M, CurrencyCode="USD", },
new(){ Id=1218, ProviderId=12, Name="o1-preview", ShortName=null, IsLegacy=true, MinTemperature=1.00M, MaxTemperature=1.00M, AllowSearch=false, AllowVision=false, AllowSystemPrompt=false, AllowStreaming=false, ContextWindow=128000, MaxResponseTokens=32768, TokenizerId=null, InputTokenPrice1M=15.00000M, OutputTokenPrice1M=60.00000M, CurrencyCode="USD", },
new(){ Id=1219, ProviderId=12, Name="o1-mini", ShortName=null, IsLegacy=false, MinTemperature=1.00M, MaxTemperature=1.00M, AllowSearch=false, AllowVision=false, AllowSystemPrompt=false, AllowStreaming=false, ContextWindow=128000, MaxResponseTokens=65536, TokenizerId=null, InputTokenPrice1M=3.00000M, OutputTokenPrice1M=12.00000M, CurrencyCode="USD", },
- new(){ Id=1220, ProviderId=12, Name="o1-2024-12-17", ShortName="o1", IsLegacy=false, MinTemperature=1.00M, MaxTemperature=1.00M, AllowSearch=false, AllowVision=true, AllowSystemPrompt=true, AllowStreaming=false, ContextWindow=200000, MaxResponseTokens=100000, TokenizerId=2, InputTokenPrice1M=15.00000M, OutputTokenPrice1M=60.00000M, CurrencyCode="USD", }
+ new(){ Id=1220, ProviderId=12, Name="o1-2024-12-17", ShortName="o1", IsLegacy=false, MinTemperature=1.00M, MaxTemperature=1.00M, AllowSearch=false, AllowVision=true, AllowSystemPrompt=true, AllowStreaming=false, ContextWindow=200000, MaxResponseTokens=100000, TokenizerId=2, InputTokenPrice1M=15.00000M, OutputTokenPrice1M=60.00000M, CurrencyCode="USD", },
+ new(){ Id=1300, ProviderId=13, Name="gemini-2.0-flash-thinking-exp", ShortName="gemini", IsLegacy=false, MinTemperature=0.00M, MaxTemperature=2.00M, AllowSearch=false, AllowVision=true, AllowSystemPrompt=true, AllowStreaming=true, ContextWindow=40000, MaxResponseTokens=8000, TokenizerId=null, InputTokenPrice1M=0.00000M, OutputTokenPrice1M=0.00000M, CurrencyCode="USD", },
+ new(){ Id=1301, ProviderId=13, Name="gemini-2.0-flash-exp", ShortName="gemini", IsLegacy=false, MinTemperature=0.00M, MaxTemperature=2.00M, AllowSearch=false, AllowVision=true, AllowSystemPrompt=true, AllowStreaming=true, ContextWindow=1048576, MaxResponseTokens=8000, TokenizerId=null, InputTokenPrice1M=0.00000M, OutputTokenPrice1M=0.00000M, CurrencyCode="USD", },
+ new(){ Id=1302, ProviderId=13, Name="gemini-exp-1206", ShortName="gemini", IsLegacy=false, MinTemperature=0.00M, MaxTemperature=2.00M, AllowSearch=false, AllowVision=true, AllowSystemPrompt=true, AllowStreaming=true, ContextWindow=2097152, MaxResponseTokens=8000, TokenizerId=null, InputTokenPrice1M=0.00000M, OutputTokenPrice1M=0.00000M, CurrencyCode="USD", },
+ new(){ Id=1400, ProviderId=14, Name="general", ShortName=null, IsLegacy=false, MinTemperature=0.00M, MaxTemperature=2.00M, AllowSearch=false, AllowVision=false, AllowSystemPrompt=true, AllowStreaming=true, ContextWindow=128000, MaxResponseTokens=8000, TokenizerId=null, InputTokenPrice1M=0.00000M, OutputTokenPrice1M=0.00000M, CurrencyCode="RMB", },
+ new(){ Id=1401, ProviderId=14, Name="general-vision", ShortName=null, IsLegacy=false, MinTemperature=0.00M, MaxTemperature=2.00M, AllowSearch=false, AllowVision=true, AllowSystemPrompt=true, AllowStreaming=true, ContextWindow=128000, MaxResponseTokens=8000, TokenizerId=null, InputTokenPrice1M=0.00000M, OutputTokenPrice1M=0.00000M, CurrencyCode="RMB", },
+ new(){ Id=1500, ProviderId=15, Name="MiniMax-Text-01", ShortName=null, IsLegacy=false, MinTemperature=0.00M, MaxTemperature=2.00M, AllowSearch=false, AllowVision=true, AllowSystemPrompt=true, AllowStreaming=true, ContextWindow=1000000, MaxResponseTokens=8000, TokenizerId=null, InputTokenPrice1M=1.00000M, OutputTokenPrice1M=8.00000M, CurrencyCode="RMB", }
]);
}
private static void InsertModelProviders(ChatsDB db)
{
- // Generated from data, hash: 615290985867eb3467e7889a31c4edf5dcdbd113930d67df8e19b6cd27c955ca
+ // Generated from data, hash: 3746cc1a6f22a05f83d27814361078fef50de0cd7b5e777e0c55e1840525f843
db.ModelProviders.AddRange(
[
new(){ Id=0, Name="Test", InitialHost=null, InitialSecret=null, },
@@ -269,7 +275,10 @@ private static void InsertModelProviders(ChatsDB db)
new(){ Id=9, Name="Zhipu AI", InitialHost=null, InitialSecret="", },
new(){ Id=10, Name="DeepSeek", InitialHost=null, InitialSecret="", },
new(){ Id=11, Name="x.ai", InitialHost=null, InitialSecret="xai-yourkey", },
- new(){ Id=12, Name="Github Models", InitialHost=null, InitialSecret="ghp_yourkey", }
+ new(){ Id=12, Name="Github Models", InitialHost=null, InitialSecret="ghp_yourkey", },
+ new(){ Id=13, Name="Google AI", InitialHost=null, InitialSecret="", },
+ new(){ Id=14, Name="Ollama", InitialHost="http://localhost:11434/v1", InitialSecret="ollama", },
+ new(){ Id=15, Name="MiniMax", InitialHost=null, InitialSecret="your-key", }
]);
}
};
\ No newline at end of file
diff --git a/src/BE/DB/Init/InitService.cs b/src/BE/DB/Init/InitService.cs
index bc54235d..7aa74b29 100644
--- a/src/BE/DB/Init/InitService.cs
+++ b/src/BE/DB/Init/InitService.cs
@@ -23,9 +23,6 @@ public async Task Init(CancellationToken cancellationToken = default)
private static async Task InsertInitialData(IServiceScope scope, ChatsDB db, CancellationToken cancellationToken)
{
- JwtKeyManager jwtKeyManager = scope.ServiceProvider.GetRequiredService();
- await jwtKeyManager.GetOrCreateSecretKey(cancellationToken);
-
BasicData.InsertAll(db);
await db.SaveChangesAsync(cancellationToken);
diff --git a/src/BE/DB/ModelKey.cs b/src/BE/DB/ModelKey.cs
index 34ebe1d6..23aedb00 100644
--- a/src/BE/DB/ModelKey.cs
+++ b/src/BE/DB/ModelKey.cs
@@ -22,7 +22,7 @@ public partial class ModelKey
[Unicode(false)]
public string? Host { get; set; }
- [StringLength(500)]
+ [StringLength(1000)]
[Unicode(false)]
public string? Secret { get; set; }
diff --git a/src/BE/Program.cs b/src/BE/Program.cs
index 690d1416..f33f2088 100644
--- a/src/BE/Program.cs
+++ b/src/BE/Program.cs
@@ -3,7 +3,7 @@
using Chats.BE.Infrastructure;
using Chats.BE.Services;
using Chats.BE.Services.Configs;
-using Chats.BE.Services.ChatServices;
+using Chats.BE.Services.Models;
using Chats.BE.Services.UrlEncryption;
using Chats.BE.Services.OpenAIApiKeySession;
using Chats.BE.Services.Sessions;
@@ -45,7 +45,7 @@ public static async Task Main(string[] args)
builder.Services.AddSingleton();
builder.Services.AddScoped();
builder.Services.AddScoped();
- builder.Services.AddScoped();
+ builder.Services.AddSingleton();
builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddScoped();
diff --git a/src/BE/Services/Common/FuzzyMatcher.cs b/src/BE/Services/Common/FuzzyMatcher.cs
new file mode 100644
index 00000000..6fba0892
--- /dev/null
+++ b/src/BE/Services/Common/FuzzyMatcher.cs
@@ -0,0 +1,60 @@
+namespace Chats.BE.Services.Common;
+
+using System;
+using System.Collections.Generic;
+
+public class FuzzyMatcher
+{
+ // 主函数:找到最佳匹配
+ public static string FindBestMatch(string input, HashSet options)
+ {
+ string? bestMatch = null;
+ int bestDistance = int.MaxValue;
+
+ foreach (string option in options)
+ {
+ int distance = LevenshteinDistance(input, option);
+ if (distance < bestDistance)
+ {
+ bestDistance = distance;
+ bestMatch = option;
+ }
+ }
+
+ return bestMatch!;
+ }
+
+ // 计算 Levenshtein 距离
+ private static int LevenshteinDistance(string s1, string s2)
+ {
+ int len1 = s1.Length;
+ int len2 = s2.Length;
+
+ var dp = new int[len1 + 1, len2 + 1];
+
+ for (int i = 0; i <= len1; i++)
+ {
+ for (int j = 0; j <= len2; j++)
+ {
+ if (i == 0)
+ {
+ dp[i, j] = j;
+ }
+ else if (j == 0)
+ {
+ dp[i, j] = i;
+ }
+ else
+ {
+ int cost = s1[i - 1] == s2[j - 1] ? 0 : 1;
+ dp[i, j] = Math.Min(
+ Math.Min(dp[i - 1, j] + 1, dp[i, j - 1] + 1),
+ dp[i - 1, j - 1] + cost
+ );
+ }
+ }
+ }
+
+ return dp[len1, len2];
+ }
+}
diff --git a/src/BE/Services/Configs/DBConfigKey.cs b/src/BE/Services/Configs/DBConfigKey.cs
index 22e0b883..971c9932 100644
--- a/src/BE/Services/Configs/DBConfigKey.cs
+++ b/src/BE/Services/Configs/DBConfigKey.cs
@@ -2,8 +2,6 @@
public static class DBConfigKey
{
- public const string JwtSecretKey = "JwtSecretKey";
-
public const string TencentSms = "tencentSms";
public const string SiteInfo = "siteInfo";
diff --git a/src/BE/Services/ChatServices/CcoWrapper.cs b/src/BE/Services/Models/CcoWrapper.cs
similarity index 97%
rename from src/BE/Services/ChatServices/CcoWrapper.cs
rename to src/BE/Services/Models/CcoWrapper.cs
index 89160158..b3fa9b90 100644
--- a/src/BE/Services/ChatServices/CcoWrapper.cs
+++ b/src/BE/Services/Models/CcoWrapper.cs
@@ -3,7 +3,7 @@
using System.Text.Json;
using System.Text.Json.Nodes;
-namespace Chats.BE.Services.ChatServices;
+namespace Chats.BE.Services.Models;
public class CcoWrapper(JsonObject json)
{
diff --git a/src/BE/Services/ChatServices/ChatExtraDetails.cs b/src/BE/Services/Models/ChatExtraDetails.cs
similarity index 85%
rename from src/BE/Services/ChatServices/ChatExtraDetails.cs
rename to src/BE/Services/Models/ChatExtraDetails.cs
index 81edbc6c..43799313 100644
--- a/src/BE/Services/ChatServices/ChatExtraDetails.cs
+++ b/src/BE/Services/Models/ChatExtraDetails.cs
@@ -1,4 +1,4 @@
-namespace Chats.BE.Services.ChatServices;
+namespace Chats.BE.Services.Models;
public record ChatExtraDetails
{
diff --git a/src/BE/Services/ChatServices/ChatFactory.cs b/src/BE/Services/Models/ChatFactory.cs
similarity index 58%
rename from src/BE/Services/ChatServices/ChatFactory.cs
rename to src/BE/Services/Models/ChatFactory.cs
index fcffa1e0..d4017af2 100644
--- a/src/BE/Services/ChatServices/ChatFactory.cs
+++ b/src/BE/Services/Models/ChatFactory.cs
@@ -1,17 +1,18 @@
using Chats.BE.DB;
using Chats.BE.DB.Enums;
-using Chats.BE.Services.ChatServices.Implementations.DashScope;
-using Chats.BE.Services.ChatServices.Implementations.Hunyuan;
-using Chats.BE.Services.ChatServices.Implementations.OpenAI;
-using Chats.BE.Services.ChatServices.Implementations.QianFan;
-using Chats.BE.Services.ChatServices.Implementations.Test;
+using Chats.BE.Services.Models.ChatServices.DashScope;
+using Chats.BE.Services.Models.ChatServices.Hunyuan;
+using Chats.BE.Services.Models.ChatServices.OpenAI;
+using Chats.BE.Services.Models.ChatServices.QianFan;
+using Chats.BE.Services.Models.ChatServices.Test;
+using Chats.BE.Services.Models.ModelLoaders;
using OpenAI.Chat;
-namespace Chats.BE.Services.ChatServices;
+namespace Chats.BE.Services.Models;
public class ChatFactory(ILogger logger)
{
- public ChatService CreateConversationService(Model model)
+ public ChatService CreateChatService(Model model)
{
DBModelProvider modelProvider = (DBModelProvider)model.ModelKey.ModelProviderId;
ChatService cs = modelProvider switch
@@ -30,14 +31,41 @@ public ChatService CreateConversationService(Model model)
DBModelProvider.xAI => new XAIChatService(model),
DBModelProvider.GithubModels => new GithubModelsChatService(model),
DBModelProvider.GoogleAI => new GoogleAIChatService(model),
+ DBModelProvider.Ollama => new OllamaChatService(model),
+ DBModelProvider.MiniMax => new MiniMaxChatService(model),
_ => throw new NotSupportedException($"Unknown model provider: {modelProvider}")
};
return cs;
}
+ public ModelLoader? CreateModelLoader(DBModelProvider modelProvider)
+ {
+ ModelLoader? ml = modelProvider switch
+ {
+ DBModelProvider.Test => null,
+ DBModelProvider.OpenAI => null,
+ DBModelProvider.AzureOpenAI => null,
+ DBModelProvider.WenXinQianFan => null,
+ DBModelProvider.AliyunDashscope => null,
+ DBModelProvider.ZhiPuAI => null,
+ DBModelProvider.Moonshot => null,
+ DBModelProvider.HunYuan => null,
+ DBModelProvider.Sparkdesk => null,
+ DBModelProvider.LingYi => null,
+ DBModelProvider.DeepSeek => null,
+ DBModelProvider.xAI => null,
+ DBModelProvider.GithubModels => null,
+ DBModelProvider.GoogleAI => null,
+ DBModelProvider.Ollama => new OpenAIModelLoader(),
+ DBModelProvider.MiniMax => null,
+ _ => throw new NotSupportedException($"Unknown model provider: {modelProvider}")
+ };
+ return ml;
+ }
+
public async Task ValidateModel(ModelKey modelKey, ModelReference modelReference, string? deploymentName, CancellationToken cancellationToken)
{
- using ChatService cs = CreateConversationService(new Model
+ using ChatService cs = CreateChatService(new Model
{
ModelKey = modelKey,
ModelReference = modelReference,
diff --git a/src/BE/Services/ChatServices/ChatService.cs b/src/BE/Services/Models/ChatService.cs
similarity index 93%
rename from src/BE/Services/ChatServices/ChatService.cs
rename to src/BE/Services/Models/ChatService.cs
index f461741d..be87d92d 100644
--- a/src/BE/Services/ChatServices/ChatService.cs
+++ b/src/BE/Services/Models/ChatService.cs
@@ -1,12 +1,12 @@
using Chats.BE.DB;
-using Chats.BE.Services.ChatServices.Dtos;
+using Chats.BE.Services.Models.Dtos;
using Tokenizer = Microsoft.ML.Tokenizers.Tokenizer;
using OpenAI.Chat;
using System.Text;
using Microsoft.ML.Tokenizers;
-using Chats.BE.Services.ChatServices.Extensions;
+using Chats.BE.Services.Models.Extensions;
-namespace Chats.BE.Services.ChatServices;
+namespace Chats.BE.Services.Models;
public abstract partial class ChatService : IDisposable
{
diff --git a/src/BE/Services/ChatServices/ChatServiceExtensions.cs b/src/BE/Services/Models/ChatServiceExtensions.cs
similarity index 97%
rename from src/BE/Services/ChatServices/ChatServiceExtensions.cs
rename to src/BE/Services/Models/ChatServiceExtensions.cs
index 5f245925..357cbe48 100644
--- a/src/BE/Services/ChatServices/ChatServiceExtensions.cs
+++ b/src/BE/Services/Models/ChatServiceExtensions.cs
@@ -1,9 +1,9 @@
-using Chats.BE.Services.ChatServices.Dtos;
-using Chats.BE.Services.ChatServices.Extensions;
+using Chats.BE.Services.Models.Dtos;
+using Chats.BE.Services.Models.Extensions;
using OpenAI.Chat;
using System.Runtime.CompilerServices;
-namespace Chats.BE.Services.ChatServices;
+namespace Chats.BE.Services.Models;
public abstract partial class ChatService
{
diff --git a/src/BE/Services/ChatServices/Implementations/DashScope/DashScopeChatService.cs b/src/BE/Services/Models/ChatServices/DashScope/DashScopeChatService.cs
similarity index 97%
rename from src/BE/Services/ChatServices/Implementations/DashScope/DashScopeChatService.cs
rename to src/BE/Services/Models/ChatServices/DashScope/DashScopeChatService.cs
index 9b425946..17c4bc51 100644
--- a/src/BE/Services/ChatServices/Implementations/DashScope/DashScopeChatService.cs
+++ b/src/BE/Services/Models/ChatServices/DashScope/DashScopeChatService.cs
@@ -1,4 +1,4 @@
-using Chats.BE.Services.ChatServices.Dtos;
+using Chats.BE.Services.Models.Dtos;
using Sdcb.DashScope;
using Sdcb.DashScope.TextGeneration;
using OpenAIChatMessage = OpenAI.Chat.ChatMessage;
@@ -9,11 +9,11 @@
using System.Runtime.CompilerServices;
using OpenAI.Chat;
using Chats.BE.DB;
-using Chats.BE.Services.ChatServices.Extensions;
+using Chats.BE.Services.Models.Extensions;
using ChatTokenUsage = Sdcb.DashScope.TextGeneration.ChatTokenUsage;
using ChatMessage = Sdcb.DashScope.TextGeneration.ChatMessage;
-namespace Chats.BE.Services.ChatServices.Implementations.DashScope;
+namespace Chats.BE.Services.Models.ChatServices.DashScope;
public class DashScopeChatService : ChatService
{
diff --git a/src/BE/Services/ChatServices/Implementations/DashScope/JsonDashScopeConfig.cs b/src/BE/Services/Models/ChatServices/DashScope/JsonDashScopeConfig.cs
similarity index 77%
rename from src/BE/Services/ChatServices/Implementations/DashScope/JsonDashScopeConfig.cs
rename to src/BE/Services/Models/ChatServices/DashScope/JsonDashScopeConfig.cs
index 945184c1..f315feaa 100644
--- a/src/BE/Services/ChatServices/Implementations/DashScope/JsonDashScopeConfig.cs
+++ b/src/BE/Services/Models/ChatServices/DashScope/JsonDashScopeConfig.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Chats.BE.Services.ChatServices.Implementations.DashScope;
+namespace Chats.BE.Services.Models.ChatServices.DashScope;
public class JsonDashScopeConfig
{
diff --git a/src/BE/Services/ChatServices/Implementations/DashScope/JsonDashScopeModelConfig.cs b/src/BE/Services/Models/ChatServices/DashScope/JsonDashScopeModelConfig.cs
similarity index 86%
rename from src/BE/Services/ChatServices/Implementations/DashScope/JsonDashScopeModelConfig.cs
rename to src/BE/Services/Models/ChatServices/DashScope/JsonDashScopeModelConfig.cs
index b52ee969..b9f9a6ff 100644
--- a/src/BE/Services/ChatServices/Implementations/DashScope/JsonDashScopeModelConfig.cs
+++ b/src/BE/Services/Models/ChatServices/DashScope/JsonDashScopeModelConfig.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Chats.BE.Services.ChatServices.Implementations.DashScope;
+namespace Chats.BE.Services.Models.ChatServices.DashScope;
public record JsonDashScopeModelConfig
{
diff --git a/src/BE/Services/ChatServices/Implementations/Hunyuan/HunyuanChatService.cs b/src/BE/Services/Models/ChatServices/Hunyuan/HunyuanChatService.cs
similarity index 97%
rename from src/BE/Services/ChatServices/Implementations/Hunyuan/HunyuanChatService.cs
rename to src/BE/Services/Models/ChatServices/Hunyuan/HunyuanChatService.cs
index fcda09f0..cfef14c2 100644
--- a/src/BE/Services/ChatServices/Implementations/Hunyuan/HunyuanChatService.cs
+++ b/src/BE/Services/Models/ChatServices/Hunyuan/HunyuanChatService.cs
@@ -1,4 +1,4 @@
-using Chats.BE.Services.ChatServices.Dtos;
+using Chats.BE.Services.Models.Dtos;
using OpenAI.Chat;
using System.Text.Json;
using TencentCloud.Common;
@@ -14,7 +14,7 @@
using Chats.BE.DB;
using Message = TencentCloud.Hunyuan.V20230901.Models.Message;
-namespace Chats.BE.Services.ChatServices.Implementations.Hunyuan;
+namespace Chats.BE.Services.Models.ChatServices.Hunyuan;
public class HunyuanChatService : ChatService
{
diff --git a/src/BE/Services/ChatServices/Implementations/Hunyuan/HuyuanChatSegment.cs b/src/BE/Services/Models/ChatServices/Hunyuan/HuyuanChatSegment.cs
similarity index 94%
rename from src/BE/Services/ChatServices/Implementations/Hunyuan/HuyuanChatSegment.cs
rename to src/BE/Services/Models/ChatServices/Hunyuan/HuyuanChatSegment.cs
index 420ff1a4..54be984a 100644
--- a/src/BE/Services/ChatServices/Implementations/Hunyuan/HuyuanChatSegment.cs
+++ b/src/BE/Services/Models/ChatServices/Hunyuan/HuyuanChatSegment.cs
@@ -1,4 +1,4 @@
-namespace Chats.BE.Services.ChatServices.Implementations.Hunyuan;
+namespace Chats.BE.Services.Models.ChatServices.Hunyuan;
using System.Text.Json.Serialization;
diff --git a/src/BE/Services/ChatServices/Implementations/Hunyuan/JsonHunyuanKeyConfig.cs b/src/BE/Services/Models/ChatServices/Hunyuan/JsonHunyuanKeyConfig.cs
similarity index 79%
rename from src/BE/Services/ChatServices/Implementations/Hunyuan/JsonHunyuanKeyConfig.cs
rename to src/BE/Services/Models/ChatServices/Hunyuan/JsonHunyuanKeyConfig.cs
index b681046c..12d8e548 100644
--- a/src/BE/Services/ChatServices/Implementations/Hunyuan/JsonHunyuanKeyConfig.cs
+++ b/src/BE/Services/Models/ChatServices/Hunyuan/JsonHunyuanKeyConfig.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Chats.BE.Services.ChatServices.Implementations.Hunyuan;
+namespace Chats.BE.Services.Models.ChatServices.Hunyuan;
public record JsonHunyuanKeyConfig
{
diff --git a/src/BE/Services/ChatServices/Implementations/Hunyuan/UnixDateTimeOffsetConverter.cs b/src/BE/Services/Models/ChatServices/Hunyuan/UnixDateTimeOffsetConverter.cs
similarity index 91%
rename from src/BE/Services/ChatServices/Implementations/Hunyuan/UnixDateTimeOffsetConverter.cs
rename to src/BE/Services/Models/ChatServices/Hunyuan/UnixDateTimeOffsetConverter.cs
index a968e35c..4e473339 100644
--- a/src/BE/Services/ChatServices/Implementations/Hunyuan/UnixDateTimeOffsetConverter.cs
+++ b/src/BE/Services/Models/ChatServices/Hunyuan/UnixDateTimeOffsetConverter.cs
@@ -1,7 +1,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace Chats.BE.Services.ChatServices.Implementations.Hunyuan;
+namespace Chats.BE.Services.Models.ChatServices.Hunyuan;
internal class UnixDateTimeOffsetConverter : JsonConverter
{
diff --git a/src/BE/Services/ChatServices/Implementations/OpenAI/AzureChatService.cs b/src/BE/Services/Models/ChatServices/OpenAI/AzureChatService.cs
similarity index 94%
rename from src/BE/Services/ChatServices/Implementations/OpenAI/AzureChatService.cs
rename to src/BE/Services/Models/ChatServices/OpenAI/AzureChatService.cs
index 9ef20529..044ef800 100644
--- a/src/BE/Services/ChatServices/Implementations/OpenAI/AzureChatService.cs
+++ b/src/BE/Services/Models/ChatServices/OpenAI/AzureChatService.cs
@@ -5,7 +5,7 @@
using System.ClientModel;
using System.Reflection;
-namespace Chats.BE.Services.ChatServices.Implementations.OpenAI;
+namespace Chats.BE.Services.Models.ChatServices.OpenAI;
public class AzureChatService(Model model) : OpenAIChatService(model, CreateChatClient(model))
{
@@ -15,13 +15,13 @@ static ChatClient CreateChatClient(Model model)
ArgumentException.ThrowIfNullOrWhiteSpace(model.ModelKey.Secret, nameof(model.ModelKey.Secret));
AzureOpenAIClientOptions options = new();
- if (model.ModelReference.IsSdkUnsupportedO1)
- {
- // o1 only supports api version: 2024-12-01-preview
+ if (model.ModelReference.IsSdkUnsupportedO1)
+ {
+ // o1 only supports api version: 2024-12-01-preview
options
.GetType()
.GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance)
- !.SetValue(options, "2024-12-01-preview");
+ !.SetValue(options, "2024-12-01-preview");
}
OpenAIClient api = new AzureOpenAIClient(
diff --git a/src/BE/Services/ChatServices/Implementations/OpenAI/DeepSeekChatService.cs b/src/BE/Services/Models/ChatServices/OpenAI/DeepSeekChatService.cs
similarity index 67%
rename from src/BE/Services/ChatServices/Implementations/OpenAI/DeepSeekChatService.cs
rename to src/BE/Services/Models/ChatServices/OpenAI/DeepSeekChatService.cs
index 893faa92..b57593aa 100644
--- a/src/BE/Services/ChatServices/Implementations/OpenAI/DeepSeekChatService.cs
+++ b/src/BE/Services/Models/ChatServices/OpenAI/DeepSeekChatService.cs
@@ -1,5 +1,5 @@
using Chats.BE.DB;
-namespace Chats.BE.Services.ChatServices.Implementations.OpenAI;
+namespace Chats.BE.Services.Models.ChatServices.OpenAI;
public class DeepSeekChatService(Model model) : OpenAIChatService(model, new Uri("https://api.deepseek.com/v1"));
\ No newline at end of file
diff --git a/src/BE/Services/ChatServices/Implementations/OpenAI/GLMChatService.cs b/src/BE/Services/Models/ChatServices/OpenAI/GLMChatService.cs
similarity index 69%
rename from src/BE/Services/ChatServices/Implementations/OpenAI/GLMChatService.cs
rename to src/BE/Services/Models/ChatServices/OpenAI/GLMChatService.cs
index 0e62e4dc..ca0cb42f 100644
--- a/src/BE/Services/ChatServices/Implementations/OpenAI/GLMChatService.cs
+++ b/src/BE/Services/Models/ChatServices/OpenAI/GLMChatService.cs
@@ -1,6 +1,6 @@
using Chats.BE.DB;
-namespace Chats.BE.Services.ChatServices.Implementations.OpenAI;
+namespace Chats.BE.Services.Models.ChatServices.OpenAI;
public class GLMChatService(Model model) : OpenAIChatService(model, new Uri("https://open.bigmodel.cn/api/paas/v4/"))
{
diff --git a/src/BE/Services/ChatServices/Implementations/OpenAI/GithubModelsChatService.cs b/src/BE/Services/Models/ChatServices/OpenAI/GithubModelsChatService.cs
similarity index 90%
rename from src/BE/Services/ChatServices/Implementations/OpenAI/GithubModelsChatService.cs
rename to src/BE/Services/Models/ChatServices/OpenAI/GithubModelsChatService.cs
index e45a76e3..76da78e5 100644
--- a/src/BE/Services/ChatServices/Implementations/OpenAI/GithubModelsChatService.cs
+++ b/src/BE/Services/Models/ChatServices/OpenAI/GithubModelsChatService.cs
@@ -1,7 +1,7 @@
using Chats.BE.DB;
using OpenAI.Chat;
-namespace Chats.BE.Services.ChatServices.Implementations.OpenAI;
+namespace Chats.BE.Services.Models.ChatServices.OpenAI;
public class GithubModelsChatService(Model model) : OpenAIChatService(model, new Uri("https://models.inference.ai.azure.com"))
{
diff --git a/src/BE/Services/ChatServices/Implementations/OpenAI/GoogleAIChatService.cs b/src/BE/Services/Models/ChatServices/OpenAI/GoogleAIChatService.cs
similarity index 90%
rename from src/BE/Services/ChatServices/Implementations/OpenAI/GoogleAIChatService.cs
rename to src/BE/Services/Models/ChatServices/OpenAI/GoogleAIChatService.cs
index eac83285..879946d0 100644
--- a/src/BE/Services/ChatServices/Implementations/OpenAI/GoogleAIChatService.cs
+++ b/src/BE/Services/Models/ChatServices/OpenAI/GoogleAIChatService.cs
@@ -2,7 +2,7 @@
using OpenAI.Chat;
using System.Runtime.CompilerServices;
-namespace Chats.BE.Services.ChatServices.Implementations.OpenAI;
+namespace Chats.BE.Services.Models.ChatServices.OpenAI;
public class GoogleAIChatService(Model model) : OpenAIChatService(model, new Uri("https://generativelanguage.googleapis.com/v1beta/openai/"))
{
diff --git a/src/BE/Services/ChatServices/Implementations/OpenAI/KimiChatService.cs b/src/BE/Services/Models/ChatServices/OpenAI/KimiChatService.cs
similarity index 67%
rename from src/BE/Services/ChatServices/Implementations/OpenAI/KimiChatService.cs
rename to src/BE/Services/Models/ChatServices/OpenAI/KimiChatService.cs
index b909ee68..f8e0b2bc 100644
--- a/src/BE/Services/ChatServices/Implementations/OpenAI/KimiChatService.cs
+++ b/src/BE/Services/Models/ChatServices/OpenAI/KimiChatService.cs
@@ -1,5 +1,5 @@
using Chats.BE.DB;
-namespace Chats.BE.Services.ChatServices.Implementations.OpenAI;
+namespace Chats.BE.Services.Models.ChatServices.OpenAI;
public class KimiChatService(Model model) : OpenAIChatService(model, new Uri("https://api.moonshot.cn/v1"));
\ No newline at end of file
diff --git a/src/BE/Services/ChatServices/Implementations/OpenAI/LingYiChatService.cs b/src/BE/Services/Models/ChatServices/OpenAI/LingYiChatService.cs
similarity index 68%
rename from src/BE/Services/ChatServices/Implementations/OpenAI/LingYiChatService.cs
rename to src/BE/Services/Models/ChatServices/OpenAI/LingYiChatService.cs
index 7380a7fd..ab090dd5 100644
--- a/src/BE/Services/ChatServices/Implementations/OpenAI/LingYiChatService.cs
+++ b/src/BE/Services/Models/ChatServices/OpenAI/LingYiChatService.cs
@@ -1,5 +1,5 @@
using Chats.BE.DB;
-namespace Chats.BE.Services.ChatServices.Implementations.OpenAI;
+namespace Chats.BE.Services.Models.ChatServices.OpenAI;
public class LingYiChatService(Model model) : OpenAIChatService(model, new Uri("https://api.lingyiwanwu.com/v1"));
diff --git a/src/BE/Services/Models/ChatServices/OpenAI/MiniMaxChatService.cs b/src/BE/Services/Models/ChatServices/OpenAI/MiniMaxChatService.cs
new file mode 100644
index 00000000..f46096b8
--- /dev/null
+++ b/src/BE/Services/Models/ChatServices/OpenAI/MiniMaxChatService.cs
@@ -0,0 +1,5 @@
+using Chats.BE.DB;
+
+namespace Chats.BE.Services.Models.ChatServices.OpenAI;
+
+public class MiniMaxChatService(Model model) : OpenAIChatService(model, new Uri("https://api.minimax.chat/v1"));
diff --git a/src/BE/Services/Models/ChatServices/OpenAI/OllamaChatService.cs b/src/BE/Services/Models/ChatServices/OpenAI/OllamaChatService.cs
new file mode 100644
index 00000000..02468f83
--- /dev/null
+++ b/src/BE/Services/Models/ChatServices/OpenAI/OllamaChatService.cs
@@ -0,0 +1,5 @@
+using Chats.BE.DB;
+
+namespace Chats.BE.Services.Models.ChatServices.OpenAI;
+
+public class OllamaChatService(Model model) : OpenAIChatService(model);
\ No newline at end of file
diff --git a/src/BE/Services/ChatServices/Implementations/OpenAI/OpenAIChatService.cs b/src/BE/Services/Models/ChatServices/OpenAI/OpenAIChatService.cs
similarity index 97%
rename from src/BE/Services/ChatServices/Implementations/OpenAI/OpenAIChatService.cs
rename to src/BE/Services/Models/ChatServices/OpenAI/OpenAIChatService.cs
index caf945af..2acc5235 100644
--- a/src/BE/Services/ChatServices/Implementations/OpenAI/OpenAIChatService.cs
+++ b/src/BE/Services/Models/ChatServices/OpenAI/OpenAIChatService.cs
@@ -1,4 +1,4 @@
-using Chats.BE.Services.ChatServices.Dtos;
+using Chats.BE.Services.Models.Dtos;
using OpenAI.Chat;
using OpenAI;
using System.Runtime.CompilerServices;
@@ -7,7 +7,7 @@
using System.ClientModel.Primitives;
using System.Text.Json;
-namespace Chats.BE.Services.ChatServices.Implementations.OpenAI;
+namespace Chats.BE.Services.Models.ChatServices.OpenAI;
public partial class OpenAIChatService : ChatService
{
diff --git a/src/BE/Services/ChatServices/Implementations/OpenAI/SparkDeskChatService.cs b/src/BE/Services/Models/ChatServices/OpenAI/SparkDeskChatService.cs
similarity index 93%
rename from src/BE/Services/ChatServices/Implementations/OpenAI/SparkDeskChatService.cs
rename to src/BE/Services/Models/ChatServices/OpenAI/SparkDeskChatService.cs
index 570c2d88..aae1981c 100644
--- a/src/BE/Services/ChatServices/Implementations/OpenAI/SparkDeskChatService.cs
+++ b/src/BE/Services/Models/ChatServices/OpenAI/SparkDeskChatService.cs
@@ -1,7 +1,7 @@
using Chats.BE.DB;
using OpenAI.Chat;
-namespace Chats.BE.Services.ChatServices.Implementations.OpenAI;
+namespace Chats.BE.Services.Models.ChatServices.OpenAI;
public class SparkDeskChatService(Model model) : OpenAIChatService(model, new Uri("https://spark-api-open.xf-yun.com/v1"))
{
diff --git a/src/BE/Services/ChatServices/Implementations/OpenAI/XAIChatService.cs b/src/BE/Services/Models/ChatServices/OpenAI/XAIChatService.cs
similarity index 65%
rename from src/BE/Services/ChatServices/Implementations/OpenAI/XAIChatService.cs
rename to src/BE/Services/Models/ChatServices/OpenAI/XAIChatService.cs
index 338018ab..e600e66c 100644
--- a/src/BE/Services/ChatServices/Implementations/OpenAI/XAIChatService.cs
+++ b/src/BE/Services/Models/ChatServices/OpenAI/XAIChatService.cs
@@ -1,5 +1,5 @@
using Chats.BE.DB;
-namespace Chats.BE.Services.ChatServices.Implementations.OpenAI;
+namespace Chats.BE.Services.Models.ChatServices.OpenAI;
public class XAIChatService(Model model) : OpenAIChatService(model, new Uri("https://api.x.ai/v1"));
\ No newline at end of file
diff --git a/src/BE/Services/ChatServices/Implementations/QianFan/JsonQianFanApiConfig.cs b/src/BE/Services/Models/ChatServices/QianFan/JsonQianFanApiConfig.cs
similarity index 78%
rename from src/BE/Services/ChatServices/Implementations/QianFan/JsonQianFanApiConfig.cs
rename to src/BE/Services/Models/ChatServices/QianFan/JsonQianFanApiConfig.cs
index 36fdb87d..b2561eaf 100644
--- a/src/BE/Services/ChatServices/Implementations/QianFan/JsonQianFanApiConfig.cs
+++ b/src/BE/Services/Models/ChatServices/QianFan/JsonQianFanApiConfig.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Chats.BE.Services.ChatServices.Implementations.QianFan;
+namespace Chats.BE.Services.Models.ChatServices.QianFan;
public record JsonQianFanApiConfig
{
diff --git a/src/BE/Services/ChatServices/Implementations/QianFan/JsonQianFanModelConfig.cs b/src/BE/Services/Models/ChatServices/QianFan/JsonQianFanModelConfig.cs
similarity index 86%
rename from src/BE/Services/ChatServices/Implementations/QianFan/JsonQianFanModelConfig.cs
rename to src/BE/Services/Models/ChatServices/QianFan/JsonQianFanModelConfig.cs
index 851a1596..083176e1 100644
--- a/src/BE/Services/ChatServices/Implementations/QianFan/JsonQianFanModelConfig.cs
+++ b/src/BE/Services/Models/ChatServices/QianFan/JsonQianFanModelConfig.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Chats.BE.Services.ChatServices.Implementations.QianFan;
+namespace Chats.BE.Services.Models.ChatServices.QianFan;
public record JsonQianFanModelConfig
{
diff --git a/src/BE/Services/ChatServices/Implementations/QianFan/QianFanChatService.cs b/src/BE/Services/Models/ChatServices/QianFan/QianFanChatService.cs
similarity index 95%
rename from src/BE/Services/ChatServices/Implementations/QianFan/QianFanChatService.cs
rename to src/BE/Services/Models/ChatServices/QianFan/QianFanChatService.cs
index 2a1780d7..378a96c8 100644
--- a/src/BE/Services/ChatServices/Implementations/QianFan/QianFanChatService.cs
+++ b/src/BE/Services/Models/ChatServices/QianFan/QianFanChatService.cs
@@ -1,4 +1,4 @@
-using Chats.BE.Services.ChatServices.Dtos;
+using Chats.BE.Services.Models.Dtos;
using Sdcb.WenXinQianFan;
using System.Runtime.CompilerServices;
using System.Text.Json;
@@ -10,9 +10,9 @@
using ChatMessage = Sdcb.WenXinQianFan.ChatMessage;
using Chats.BE.DB;
using OpenAI.Chat;
-using Chats.BE.Services.ChatServices.Extensions;
+using Chats.BE.Services.Models.Extensions;
-namespace Chats.BE.Services.ChatServices.Implementations.QianFan;
+namespace Chats.BE.Services.Models.ChatServices.QianFan;
public class QianFanChatService : ChatService
{
diff --git a/src/BE/Services/ChatServices/Implementations/Test/TestChatService.cs b/src/BE/Services/Models/ChatServices/Test/TestChatService.cs
similarity index 97%
rename from src/BE/Services/ChatServices/Implementations/Test/TestChatService.cs
rename to src/BE/Services/Models/ChatServices/Test/TestChatService.cs
index 1f707212..864b4bf8 100644
--- a/src/BE/Services/ChatServices/Implementations/Test/TestChatService.cs
+++ b/src/BE/Services/Models/ChatServices/Test/TestChatService.cs
@@ -1,10 +1,10 @@
using Chats.BE.DB;
-using Chats.BE.Services.ChatServices.Dtos;
+using Chats.BE.Services.Models.Dtos;
using OpenAI.Chat;
using System.Runtime.CompilerServices;
using System.Text;
-namespace Chats.BE.Services.ChatServices.Implementations.Test;
+namespace Chats.BE.Services.Models.ChatServices.Test;
public class TestChatService(Model model) : ChatService(model)
{
diff --git a/src/BE/Services/ChatServices/ChatStopService.cs b/src/BE/Services/Models/ChatStopService.cs
similarity index 97%
rename from src/BE/Services/ChatServices/ChatStopService.cs
rename to src/BE/Services/Models/ChatStopService.cs
index 00359617..33fef8a3 100644
--- a/src/BE/Services/ChatServices/ChatStopService.cs
+++ b/src/BE/Services/Models/ChatStopService.cs
@@ -1,7 +1,7 @@
using Microsoft.AspNetCore.WebUtilities;
using System.Runtime.Caching;
-namespace Chats.BE.Services.ChatServices;
+namespace Chats.BE.Services.Models;
public class ChatStopService
{
diff --git a/src/BE/Services/ChatServices/DBChatRole.cs b/src/BE/Services/Models/DBChatRole.cs
similarity index 63%
rename from src/BE/Services/ChatServices/DBChatRole.cs
rename to src/BE/Services/Models/DBChatRole.cs
index 2b490202..2b024a4c 100644
--- a/src/BE/Services/ChatServices/DBChatRole.cs
+++ b/src/BE/Services/Models/DBChatRole.cs
@@ -1,4 +1,4 @@
-namespace Chats.BE.Services.ChatServices;
+namespace Chats.BE.Services.Models;
public enum DBChatRole
{
diff --git a/src/BE/Services/ChatServices/DBFinishReason.cs b/src/BE/Services/Models/DBFinishReason.cs
similarity index 87%
rename from src/BE/Services/ChatServices/DBFinishReason.cs
rename to src/BE/Services/Models/DBFinishReason.cs
index 58ae1e7d..d7f1a95c 100644
--- a/src/BE/Services/ChatServices/DBFinishReason.cs
+++ b/src/BE/Services/Models/DBFinishReason.cs
@@ -1,4 +1,4 @@
-namespace Chats.BE.Services.ChatServices;
+namespace Chats.BE.Services.Models;
public enum DBFinishReason : byte
{
diff --git a/src/BE/Services/ChatServices/Dtos/ChatSegment.cs b/src/BE/Services/Models/Dtos/ChatSegment.cs
similarity index 95%
rename from src/BE/Services/ChatServices/Dtos/ChatSegment.cs
rename to src/BE/Services/Models/Dtos/ChatSegment.cs
index 76439448..65607f8f 100644
--- a/src/BE/Services/ChatServices/Dtos/ChatSegment.cs
+++ b/src/BE/Services/Models/Dtos/ChatSegment.cs
@@ -1,6 +1,6 @@
using OpenAI.Chat;
-namespace Chats.BE.Services.ChatServices.Dtos;
+namespace Chats.BE.Services.Models.Dtos;
public record ChatSegment
{
diff --git a/src/BE/Services/ChatServices/Dtos/ChatTokenUsage.cs b/src/BE/Services/Models/Dtos/ChatTokenUsage.cs
similarity index 87%
rename from src/BE/Services/ChatServices/Dtos/ChatTokenUsage.cs
rename to src/BE/Services/Models/Dtos/ChatTokenUsage.cs
index 2bbdec75..d5b2e322 100644
--- a/src/BE/Services/ChatServices/Dtos/ChatTokenUsage.cs
+++ b/src/BE/Services/Models/Dtos/ChatTokenUsage.cs
@@ -1,4 +1,4 @@
-namespace Chats.BE.Services.ChatServices.Dtos;
+namespace Chats.BE.Services.Models.Dtos;
public record ChatTokenUsage
{
diff --git a/src/BE/Services/ChatServices/Dtos/InternalChatSegment.cs b/src/BE/Services/Models/Dtos/InternalChatSegment.cs
similarity index 98%
rename from src/BE/Services/ChatServices/Dtos/InternalChatSegment.cs
rename to src/BE/Services/Models/Dtos/InternalChatSegment.cs
index 63d89e17..9493973f 100644
--- a/src/BE/Services/ChatServices/Dtos/InternalChatSegment.cs
+++ b/src/BE/Services/Models/Dtos/InternalChatSegment.cs
@@ -1,7 +1,7 @@
using Chats.BE.Controllers.OpenAICompatible.Dtos;
using OpenAI.Chat;
-namespace Chats.BE.Services.ChatServices.Dtos;
+namespace Chats.BE.Services.Models.Dtos;
public record InternalChatSegment
{
diff --git a/src/BE/Services/ChatServices/Extensions/ChatCompletionOptionsExtensions.cs b/src/BE/Services/Models/Extensions/ChatCompletionOptionsExtensions.cs
similarity index 98%
rename from src/BE/Services/ChatServices/Extensions/ChatCompletionOptionsExtensions.cs
rename to src/BE/Services/Models/Extensions/ChatCompletionOptionsExtensions.cs
index d1ee37d8..9e9d4609 100644
--- a/src/BE/Services/ChatServices/Extensions/ChatCompletionOptionsExtensions.cs
+++ b/src/BE/Services/Models/Extensions/ChatCompletionOptionsExtensions.cs
@@ -2,7 +2,7 @@
using System.Reflection;
using System.Runtime.CompilerServices;
-namespace Chats.BE.Services.ChatServices.Extensions;
+namespace Chats.BE.Services.Models.Extensions;
public static class ChatCompletionOptionsExtensions
{
diff --git a/src/BE/Services/ChatServices/Extensions/ChatMessageContentPartExtensions.cs b/src/BE/Services/Models/Extensions/ChatMessageContentPartExtensions.cs
similarity index 92%
rename from src/BE/Services/ChatServices/Extensions/ChatMessageContentPartExtensions.cs
rename to src/BE/Services/Models/Extensions/ChatMessageContentPartExtensions.cs
index 07b35aef..17d715a7 100644
--- a/src/BE/Services/ChatServices/Extensions/ChatMessageContentPartExtensions.cs
+++ b/src/BE/Services/Models/Extensions/ChatMessageContentPartExtensions.cs
@@ -1,7 +1,7 @@
using Microsoft.ML.Tokenizers;
using OpenAI.Chat;
-namespace Chats.BE.Services.ChatServices.Extensions;
+namespace Chats.BE.Services.Models.Extensions;
public static class ChatMessageContentPartExtensions
{
diff --git a/src/BE/Services/ChatServices/Extensions/ChatMessageExtensions.cs b/src/BE/Services/Models/Extensions/ChatMessageExtensions.cs
similarity index 85%
rename from src/BE/Services/ChatServices/Extensions/ChatMessageExtensions.cs
rename to src/BE/Services/Models/Extensions/ChatMessageExtensions.cs
index c5a1f845..f5ee3c58 100644
--- a/src/BE/Services/ChatServices/Extensions/ChatMessageExtensions.cs
+++ b/src/BE/Services/Models/Extensions/ChatMessageExtensions.cs
@@ -1,7 +1,7 @@
using Microsoft.ML.Tokenizers;
using OpenAI.Chat;
-namespace Chats.BE.Services.ChatServices.Extensions;
+namespace Chats.BE.Services.Models.Extensions;
public static class ChatMessageExtensions
{
diff --git a/src/BE/Services/ChatServices/InChatContext.cs b/src/BE/Services/Models/InChatContext.cs
similarity index 98%
rename from src/BE/Services/ChatServices/InChatContext.cs
rename to src/BE/Services/Models/InChatContext.cs
index 46069208..a56442d9 100644
--- a/src/BE/Services/ChatServices/InChatContext.cs
+++ b/src/BE/Services/Models/InChatContext.cs
@@ -3,11 +3,11 @@
using Chats.BE.DB.Enums;
using Chats.BE.DB.Jsons;
using Chats.BE.Services.Common;
-using Chats.BE.Services.ChatServices.Dtos;
+using Chats.BE.Services.Models.Dtos;
using System.Diagnostics;
using System.Text;
-namespace Chats.BE.Services.ChatServices;
+namespace Chats.BE.Services.Models;
public class InChatContext(long firstTick)
{
diff --git a/src/BE/Services/Models/ModelLoader.cs b/src/BE/Services/Models/ModelLoader.cs
new file mode 100644
index 00000000..abf993e3
--- /dev/null
+++ b/src/BE/Services/Models/ModelLoader.cs
@@ -0,0 +1,8 @@
+using Chats.BE.DB;
+
+namespace Chats.BE.Services.Models;
+
+public abstract class ModelLoader
+{
+ public abstract Task ListModels(ModelKey modelKey, CancellationToken cancellationToken);
+}
diff --git a/src/BE/Services/Models/ModelLoaders/OpenAIModelLoader.cs b/src/BE/Services/Models/ModelLoaders/OpenAIModelLoader.cs
new file mode 100644
index 00000000..f66f8ef7
--- /dev/null
+++ b/src/BE/Services/Models/ModelLoaders/OpenAIModelLoader.cs
@@ -0,0 +1,21 @@
+using Chats.BE.DB;
+using OpenAI;
+using OpenAI.Models;
+using System.ClientModel;
+
+namespace Chats.BE.Services.Models.ModelLoaders;
+
+public class OpenAIModelLoader : ModelLoader
+{
+ public override async Task ListModels(ModelKey modelKey, CancellationToken cancellationToken)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(modelKey.Secret, nameof(modelKey.Secret));
+
+ OpenAIClient api = new(new ApiKeyCredential(modelKey.Secret), new OpenAIClientOptions()
+ {
+ Endpoint = !string.IsNullOrWhiteSpace(modelKey.Host) ? new Uri(modelKey.Host) : null,
+ });
+ ClientResult result = await api.GetOpenAIModelClient().GetModelsAsync(cancellationToken);
+ return result.Value.Select(m => m.Id).ToArray();
+ }
+}
diff --git a/src/BE/Services/ChatServices/ModelValidateResult.cs b/src/BE/Services/Models/ModelValidateResult.cs
similarity index 93%
rename from src/BE/Services/ChatServices/ModelValidateResult.cs
rename to src/BE/Services/Models/ModelValidateResult.cs
index 78ba76f1..066361eb 100644
--- a/src/BE/Services/ChatServices/ModelValidateResult.cs
+++ b/src/BE/Services/Models/ModelValidateResult.cs
@@ -1,7 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-namespace Chats.BE.Services.ChatServices;
+namespace Chats.BE.Services.Models;
public record ModelValidateResult
{
diff --git a/src/BE/Services/Sessions/JwtKeyManager.cs b/src/BE/Services/Sessions/JwtKeyManager.cs
index f476cb4d..73715904 100644
--- a/src/BE/Services/Sessions/JwtKeyManager.cs
+++ b/src/BE/Services/Sessions/JwtKeyManager.cs
@@ -1,28 +1,21 @@
-using Chats.BE.DB;
-using Chats.BE.Services.Configs;
-using Microsoft.EntityFrameworkCore;
+using System.Configuration;
namespace Chats.BE.Services.Sessions;
-public class JwtKeyManager(ChatsDB db)
+public class JwtKeyManager(IConfiguration configuration)
{
- public async Task GetOrCreateSecretKey(CancellationToken cancellationToken)
+ public string GetOrCreateSecretKey()
{
- // check environment variable first
- // if it's not set, then generate a new one and store into database
- string? secretKey = Environment.GetEnvironmentVariable("JWT_SECRET_KEY");
- if (secretKey != null) return secretKey;
-
- string? configText = await db.Configs
- .Where(s => s.Key == DBConfigKey.JwtSecretKey)
- .Select(x => x.Value)
- .SingleOrDefaultAsync(cancellationToken);
- if (configText != null) return configText;
-
- string generated = Guid.NewGuid().ToString();
- db.Configs.Add(new Config { Key = DBConfigKey.JwtSecretKey, Value = generated, Description = $"Generated at {DateTime.Now:O}" });
- await db.SaveChangesAsync(cancellationToken);
-
- return generated;
+ string? secretKey = configuration["JWT_SECRET_KEY"];
+ if (secretKey != null)
+ {
+ return secretKey;
+ }
+ else
+ {
+ string generated = Guid.NewGuid().ToString();
+ configuration["JWT_SECRET_KEY"] = generated;
+ return generated;
+ }
}
}
diff --git a/src/BE/Services/Sessions/SessionManager.cs b/src/BE/Services/Sessions/SessionManager.cs
index 53382df2..a1324268 100644
--- a/src/BE/Services/Sessions/SessionManager.cs
+++ b/src/BE/Services/Sessions/SessionManager.cs
@@ -13,10 +13,10 @@ public class SessionManager(JwtKeyManager jwtKeyManager)
private const string ValidAudience = "chats";
private static readonly TimeSpan ValidPeriod = TimeSpan.FromHours(8);
- public async Task GetCachedUserInfoBySession(string jwt, CancellationToken cancellationToken = default)
+ public Task GetCachedUserInfoBySession(string jwt, CancellationToken _ = default)
{
- ClaimsPrincipal claims = ValidateJwt(jwt, await GetSecurityKey(cancellationToken));
- return SessionEntry.FromClaims(claims);
+ ClaimsPrincipal claims = ValidateJwt(jwt, GetSecurityKey());
+ return Task.FromResult(SessionEntry.FromClaims(claims));
}
private static ClaimsPrincipal ValidateJwt(string jwt, SecurityKey signingKey)
@@ -51,11 +51,11 @@ internal static byte[] Pdkdf2StringToByte32(string input)
return new Rfc2898DeriveBytes(input, salt, 10000, HashAlgorithmName.SHA256).GetBytes(32);
}
- private async Task GetSecurityKey(CancellationToken cancellationToken) => new(Pdkdf2StringToByte32(await jwtKeyManager.GetOrCreateSecretKey(cancellationToken)));
+ private SymmetricSecurityKey GetSecurityKey() => new(Pdkdf2StringToByte32(jwtKeyManager.GetOrCreateSecretKey()));
- public async Task GenerateSessionForUser(User user, CancellationToken cancellationToken)
+ public Task GenerateSessionForUser(User user, CancellationToken _)
{
- SigningCredentials cred = new(await GetSecurityKey(cancellationToken), SecurityAlgorithms.HmacSha256);
+ SigningCredentials cred = new(GetSecurityKey(), SecurityAlgorithms.HmacSha256);
SessionEntry sessionEntry = new()
{
UserId = user.Id,
@@ -73,12 +73,12 @@ public async Task GenerateSessionForUser(User user, CancellationT
string jwt = new JwtSecurityTokenHandler().WriteToken(token);
bool hasPayService = false;
- return new LoginResponse
+ return Task.FromResult(new LoginResponse
{
SessionId = jwt,
UserName = user.DisplayName,
Role = user.Role,
CanReCharge = hasPayService,
- };
+ });
}
}
diff --git a/src/FE/apis/adminApis.ts b/src/FE/apis/adminApis.ts
index ca938b28..ceb05194 100644
--- a/src/FE/apis/adminApis.ts
+++ b/src/FE/apis/adminApis.ts
@@ -262,13 +262,6 @@ export const deleteModelKeys = (id: number) => {
return fetchService.delete(`/api/admin/model-keys/${id}`);
};
-export const postAutoCreateModels = (modelKey: number) => {
- const fetchService = useFetch();
- return fetchService.post(
- `/api/admin/model-keys/${modelKey}/auto-create-models`,
- );
-};
-
export const getUserInitialConfig = () => {
const fetchServer = useFetch();
return fetchServer.get(
diff --git a/src/FE/locales/zh-CN.json b/src/FE/locales/zh-CN.json
index dbdf03f2..ac5c169f 100644
--- a/src/FE/locales/zh-CN.json
+++ b/src/FE/locales/zh-CN.json
@@ -213,6 +213,7 @@
"Rank": "#",
"ID": "模型",
"Model Display Name": "模型显示名称",
+ "Model Reference Name": "模型参考名称",
"Model Key": "模型密钥",
"Model Type": "模型类型",
"Model Provider": "模型提供商",
diff --git a/src/FE/pages/admin/_components/ModelKeys/ConfigModelModal.tsx b/src/FE/pages/admin/_components/ModelKeys/ConfigModelModal.tsx
index 98916bba..0059aa84 100644
--- a/src/FE/pages/admin/_components/ModelKeys/ConfigModelModal.tsx
+++ b/src/FE/pages/admin/_components/ModelKeys/ConfigModelModal.tsx
@@ -128,6 +128,10 @@ const ConfigModelModal = (props: IProps) => {
setModels(modelList);
}
+ function needDeploymentName(modelProviderId: DBModelProvider) {
+ return modelProviderId === DBModelProvider.AzureOpenAI || modelProviderId === DBModelProvider.Ollama;
+ }
+
return (