Personen Navigation funktioniert - doppelte oid
Beide OpenWebUi + ollama support
This commit is contained in:
@@ -14,8 +14,8 @@ namespace AICore.Context.EntryMapper
|
||||
//pContext.CustomerOid = "---";
|
||||
//pContext.EmployeeOid = "---";
|
||||
pContext.FullName = pObject.FirstNameLastName;
|
||||
pContext.Geschlecht = pObject.Sex.ToString();
|
||||
pContext.Function = pObject.Function.Value;
|
||||
pContext.Geschlecht = pObject.Sex?.ToString();
|
||||
pContext.Function = pObject.Function?.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace AICore.Facade.LLM
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
var data = response.Data.models.Select(x => new AiModelDC(x.name, x.details.max_context_size));
|
||||
var data = response.Data.models.Select(x => new AiModelDC(BS.Shared.AiModelSource.ollama, x.name, x.details.max_context_size));
|
||||
|
||||
return ApiResponse<IEnumerable<AiModelDC>>.SuccessResponse(data);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace AICore.Facade.LLM
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
var data = response.Data.data.Select(x => new AiModelDC(x.name, x.details.max_context_size));
|
||||
var data = response.Data.data.Select(x => new AiModelDC(BS.Shared.AiModelSource.openwebui, x.name, x.details?.max_context_size ?? -2));
|
||||
|
||||
return ApiResponse<IEnumerable<AiModelDC>>.SuccessResponse(data);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace BeWo
|
||||
|
||||
public static string ShortVersion = "3.26";
|
||||
|
||||
public static string Version = "Version 3.26 - 1.2.1 Test";
|
||||
public static string Version = "Version 3.26 - 1.3 AI Test";
|
||||
|
||||
public static int RenderTier = 0;
|
||||
public static bool IsInDesignMode = DesignerProperties.GetIsInDesignMode(new DependencyObject());
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
IsEnabled="False"
|
||||
Value="{Binding Config.Temperature}" />
|
||||
Value="{Binding Config.Temperature}"/>
|
||||
|
||||
<Label Grid.Row="2" IsEnabled="False">
|
||||
top__p
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -197,7 +197,7 @@ namespace BeWo.View.Navigation
|
||||
}
|
||||
|
||||
var dict = new Dictionary<TableID, long[]>() {
|
||||
{ TableID.Customer, oids.ToArray()}
|
||||
{ TableID.Customer, oids.Distinct().ToArray()}
|
||||
};
|
||||
|
||||
return dict;
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace BeWo.View.Navigation
|
||||
}
|
||||
|
||||
var dict = new Dictionary<TableID, long[]>() {
|
||||
{ TableID.Employee, oids.ToArray()}
|
||||
{ TableID.Employee, oids.Distinct().ToArray()}
|
||||
};
|
||||
|
||||
return dict;
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace BeWo.View.Navigation
|
||||
|
||||
var dict = new Dictionary<TableID, long[]>() {
|
||||
{
|
||||
TableID.Organisation, oids.ToArray()}
|
||||
TableID.Organisation, oids.Distinct().ToArray()}
|
||||
};
|
||||
|
||||
return dict;
|
||||
|
||||
@@ -21,6 +21,7 @@ using System.Collections;
|
||||
using System.Windows.Input;
|
||||
using BeWo.Core.Commands;
|
||||
using BeWo.ViewModel.View;
|
||||
using DevExpress.XtraBars.Docking;
|
||||
|
||||
namespace BeWo.View.Navigation
|
||||
{
|
||||
@@ -106,7 +107,7 @@ namespace BeWo.View.Navigation
|
||||
|
||||
var dict = new Dictionary<TableID, long[]>() {
|
||||
{
|
||||
TableID.Person, oids.ToArray()}
|
||||
TableID.Person, oids.Distinct().ToArray()}
|
||||
};
|
||||
|
||||
return dict;
|
||||
|
||||
@@ -220,7 +220,7 @@ namespace BeWo.View.Navigation
|
||||
|
||||
var dict = new Dictionary<TableID, long[]>() {
|
||||
{
|
||||
TableID.SupportConcept, oids.ToArray()}
|
||||
TableID.SupportConcept, oids.Distinct().ToArray()}
|
||||
};
|
||||
|
||||
return dict;
|
||||
|
||||
@@ -14,18 +14,18 @@
|
||||
<binding name="BeWoBasicEndpoint" closeTimeout="00:05:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true" messageEncoding="Text">
|
||||
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
|
||||
<!--<security mode="None" />-->
|
||||
<security mode="None" />
|
||||
<security mode="Transport" />
|
||||
<!-- mode="Transport" für https und "None" sonst-->
|
||||
</binding>
|
||||
<binding name="BeWoStreamingEndpoint" receiveTimeout="10:10:00" sendTimeout="10:01:00" maxBufferSize="65536" maxReceivedMessageSize="67108864" transferMode="StreamedRequest" useDefaultWebProxy="true" messageEncoding="Text">
|
||||
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
|
||||
<!--<security mode="None" />-->
|
||||
<security mode="None" />
|
||||
<security mode="Transport" />
|
||||
<!-- mode="Transport" für https und "None" sonst-->
|
||||
</binding>
|
||||
<binding name="QueryServiceEndpoint" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true" messageEncoding="Text">
|
||||
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
|
||||
<security mode="None">
|
||||
<security mode="Transport">
|
||||
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
|
||||
<message clientCredentialType="UserName" algorithmSuite="Default" />
|
||||
</security>
|
||||
|
||||
@@ -14,12 +14,7 @@ namespace BeWo.Data.Entities
|
||||
_Tid = TableID.AiModel;
|
||||
}
|
||||
|
||||
public AiModel(string modelName, int value) : this()
|
||||
{
|
||||
ModelName = modelName;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public virtual AiModelSource ModelSource { get; set; }
|
||||
public virtual string ModelName { get; set; }
|
||||
public virtual int Value { get; set; }
|
||||
|
||||
@@ -29,10 +24,14 @@ namespace BeWo.Data.Entities
|
||||
{
|
||||
if (other == null) return 1;
|
||||
|
||||
var comp = ModelName.CompareTo(other.ModelName);
|
||||
var comp = ModelSource.CompareTo(other.ModelSource);
|
||||
|
||||
if (comp != 0) return comp;
|
||||
|
||||
var comp1 = ModelName.CompareTo(other.ModelName);
|
||||
|
||||
if (comp1 != 0) return comp;
|
||||
|
||||
var comp2 = Value.CompareTo(other.Value);
|
||||
|
||||
return comp2;
|
||||
@@ -41,6 +40,7 @@ namespace BeWo.Data.Entities
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is AiModel ent &&
|
||||
ModelSource == ent.ModelSource &&
|
||||
ModelName == ent.ModelName &&
|
||||
Value == ent.Value;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<property name="IsActive" type="BS.Shared.ActivationTypeId, BS.Shared" />
|
||||
<property name="SystemEntryID" type="BS.Shared.SystemEntryID, BS.Shared" />
|
||||
<property name="Notice"/>
|
||||
<property name="ModelSource" type="BS.Shared.AiModelSource, BS.Shared"/>
|
||||
<property name="ModelName"/>
|
||||
<property name="Value"/>
|
||||
</class>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<NameOfLastUsedPublishProfile>C:\Projects\Bewo\BeWo - Main\Host\Properties\PublishProfiles\FolderProfile.pubxml</NameOfLastUsedPublishProfile>
|
||||
<UseIISExpress>true</UseIISExpress>
|
||||
<LastActiveSolutionConfig>Debug|Any CPU</LastActiveSolutionConfig>
|
||||
<LastActiveSolutionConfig>Release|Any CPU</LastActiveSolutionConfig>
|
||||
<Use64BitIISExpress>false</Use64BitIISExpress>
|
||||
<IISExpressSSLPort />
|
||||
<IISExpressAnonymousAuthentication />
|
||||
|
||||
@@ -7,4 +7,10 @@
|
||||
|
||||
<appSettings>
|
||||
<add key="OpenWebUIKey" value=""/>
|
||||
<add key="OllamaKey" value=""/>
|
||||
<add key="GetGkvSumApiKey" value=""/>
|
||||
<add key="DownloadReportApiKey" value=""/>
|
||||
<add key="OpenrouteServiceApiKey" value="" />
|
||||
<add key="GoogleDistanceMatrixApiKey" value="" />
|
||||
<add key="GkvSecretKey" value="" />
|
||||
</appSettings>
|
||||
2
Model/Changes_2025_07_16 AiModelSource.txt
Normal file
2
Model/Changes_2025_07_16 AiModelSource.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `aimodel`
|
||||
ADD COLUMN `ModelSource` INT NULL DEFAULT NULL AFTER `SystemEntryID`;
|
||||
@@ -18,6 +18,7 @@ namespace BeWo.Service.DCEntityMapper
|
||||
pDataContract.Oid = pEntity.Oid;
|
||||
pDataContract.Version = pEntity.Version;
|
||||
pDataContract.Notice = pEntity.Notice;
|
||||
pDataContract.ModelSource = pEntity.ModelSource;
|
||||
pDataContract.ModelName = pEntity.ModelName;
|
||||
pDataContract.Value = pEntity.Value;
|
||||
|
||||
@@ -31,6 +32,7 @@ namespace BeWo.Service.DCEntityMapper
|
||||
pEntity.Oid = pDataContract.Oid;
|
||||
pEntity.Version = pDataContract.Version;
|
||||
pEntity.Notice = pDataContract.Notice;
|
||||
pEntity.ModelSource = pDataContract.ModelSource;
|
||||
pEntity.ModelName = pDataContract.ModelName;
|
||||
pEntity.Value = pDataContract.Value;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace BeWo.Service.Plugins
|
||||
// - DBs
|
||||
|
||||
// ======================[ Config ]======================
|
||||
public AiConfigDC GetAiConfig()
|
||||
public virtual AiConfigDC GetAiConfig()
|
||||
{
|
||||
var configs = DAOFactory.GenericDAO.GetAllActive<AiConfig>();
|
||||
|
||||
@@ -48,11 +48,16 @@ namespace BeWo.Service.Plugins
|
||||
DAOFactory.GenericDAO.Insert(config);
|
||||
}
|
||||
|
||||
if (config.SelectedModel is null)
|
||||
{
|
||||
config.SelectedModel = getDefaultAiModel();
|
||||
}
|
||||
|
||||
var config_dc = MapperFactory.AiConfig.MapToNewDC(config);
|
||||
|
||||
return config_dc;
|
||||
}
|
||||
public AiConfigDC UpdateAiConfig(AiConfigDC toUpdate)
|
||||
public virtual AiConfigDC UpdateAiConfig(AiConfigDC toUpdate)
|
||||
{
|
||||
if (toUpdate?.Oid is null)
|
||||
throw new InvalidOperationException();
|
||||
@@ -69,7 +74,7 @@ namespace BeWo.Service.Plugins
|
||||
}
|
||||
|
||||
// ======================[ Models ]======================
|
||||
public IEnumerable<AiModelDC> GetAiModels()
|
||||
public virtual IEnumerable<AiModelDC> GetAiModels()
|
||||
{
|
||||
var models = getAiModels();
|
||||
|
||||
@@ -78,7 +83,7 @@ namespace BeWo.Service.Plugins
|
||||
|
||||
|
||||
// ======================[ Conversations ]======================
|
||||
public IEnumerable<AiConversationDC> GetAiConversations(AiContextType uicontext, long? oid)
|
||||
public virtual IEnumerable<AiConversationDC> GetAiConversations(AiContextType uicontext, long? oid)
|
||||
{
|
||||
// SearchDAO
|
||||
var current_user = UserRightHelper.GetLoggedInUserWithOid();
|
||||
@@ -113,7 +118,7 @@ namespace BeWo.Service.Plugins
|
||||
return dcs;
|
||||
}
|
||||
|
||||
public AiConversationDC CreateAiConversation(AiConversationDC conversation, long modell_oid)
|
||||
public virtual AiConversationDC CreateAiConversation(AiConversationDC conversation, long modell_oid)
|
||||
{
|
||||
var config = GetAiConfig();
|
||||
|
||||
@@ -123,7 +128,7 @@ namespace BeWo.Service.Plugins
|
||||
|
||||
return conv_dc;
|
||||
}
|
||||
public AiConversationDC CreateAiConversationWithMessage(AiConversationDC conversation, long modell_oid, string message)
|
||||
public virtual AiConversationDC CreateAiConversationWithMessage(AiConversationDC conversation, long modell_oid, string message)
|
||||
{
|
||||
var config = GetAiConfig();
|
||||
|
||||
@@ -135,7 +140,7 @@ namespace BeWo.Service.Plugins
|
||||
|
||||
return conv_dc;
|
||||
}
|
||||
public AiConversationDC CloneAiConversation(long conversation_oid, long? last_message_oid)
|
||||
public virtual AiConversationDC CloneAiConversation(long conversation_oid, long? last_message_oid)
|
||||
{
|
||||
var parent_conv = DAOFactory.GenericDAO.GetByID<AiConversation>(conversation_oid);
|
||||
|
||||
@@ -180,7 +185,7 @@ namespace BeWo.Service.Plugins
|
||||
return dc;
|
||||
}
|
||||
|
||||
public long UpdateAiConversationDisplayname(long oid, long version, string displayname)
|
||||
public virtual long UpdateAiConversationDisplayname(long oid, long version, string displayname)
|
||||
{
|
||||
var conv = DAOFactory.GenericDAO.GetByID<AiConversation>(oid);
|
||||
|
||||
@@ -193,7 +198,7 @@ namespace BeWo.Service.Plugins
|
||||
return conv.Version.Value;
|
||||
}
|
||||
|
||||
public void DeleteAiConversation(long conversation_oid)
|
||||
public virtual void DeleteAiConversation(long conversation_oid)
|
||||
{
|
||||
var conversation = DAOFactory.GenericDAO.LoadByID<AiConversation>(conversation_oid);
|
||||
|
||||
@@ -201,7 +206,7 @@ namespace BeWo.Service.Plugins
|
||||
}
|
||||
|
||||
// ======================[ Conversationmessages ]======================
|
||||
public AiConversationMessageDC[] SendNewMessage(long conversation, string message)
|
||||
public virtual AiConversationMessageDC[] SendNewMessage(long conversation, string message)
|
||||
{
|
||||
var conv = DAOFactory.GenericDAO.LoadByID<AiConversation>(conversation);
|
||||
|
||||
@@ -210,7 +215,7 @@ namespace BeWo.Service.Plugins
|
||||
|
||||
|
||||
// ======================[ private ]======================
|
||||
private AiConfig getDefaultAiConfig()
|
||||
protected virtual AiConfig getDefaultAiConfig()
|
||||
{
|
||||
var config = new AiConfig();
|
||||
|
||||
@@ -221,26 +226,31 @@ namespace BeWo.Service.Plugins
|
||||
|
||||
return config;
|
||||
}
|
||||
private AiModel getDefaultAiModel()
|
||||
protected virtual AiModel getDefaultAiModel()
|
||||
{
|
||||
var models = getAiModels();
|
||||
|
||||
var model = models.FirstOrDefault(x => x.ModelName.Contains("llama3.2"))
|
||||
var model = models.FirstOrDefault(x => x.ModelName.Contains("gemma3") && x.ModelName.Contains("12b") && x.ModelName.Contains("max-context"))
|
||||
?? models.FirstOrDefault(x => x.ModelName.Contains("gemma3") && x.ModelName.Contains("12b"))
|
||||
?? models.FirstOrDefault(x => x.ModelName.Contains("gemma3"))
|
||||
?? models.FirstOrDefault(x => x.ModelName.Contains("llama"))
|
||||
?? models.FirstOrDefault();
|
||||
|
||||
return model;
|
||||
}
|
||||
private IEnumerable<AiModel> getAiModels()
|
||||
protected virtual IEnumerable<AiModel> getAiModels()
|
||||
{
|
||||
var current_models = DAOFactory.GenericDAO.GetAll<AiModel>();
|
||||
var current_models_actives = current_models.Where(x => x.IsActive == ActivationTypeId.Active);
|
||||
var current_models_deactives = current_models.Where(x => x.IsActive != ActivationTypeId.Active);
|
||||
var request_models_dc = ServiceFacade.ActiveAiClient.GetAiModelle().GetResponseData();
|
||||
var request_models_dc_ollama = ServiceFacade.OllamaApiClient.GetAiModelle().GetResponseData();
|
||||
var request_models_dc_owui = ServiceFacade.OpenWebApiClient.GetAiModelle().GetResponseData();
|
||||
var request_models_dc = request_models_dc_ollama.Union(request_models_dc_owui);
|
||||
var request_models = MapperFactory.AiModel.MapToNewEntities(request_models_dc);
|
||||
|
||||
var toadd = request_models.Except(current_models);
|
||||
var toremove = current_models.Except(request_models);
|
||||
var toreadd = current_models_deactives.Intersect(toadd);
|
||||
var toremove = current_models_actives.Except(request_models);
|
||||
var toreadd = current_models_deactives.Intersect(request_models);
|
||||
|
||||
DAOFactory.GenericDAO.Insert(toadd);
|
||||
DAOFactory.GenericDAO.Deactivate(toremove);
|
||||
@@ -251,7 +261,7 @@ namespace BeWo.Service.Plugins
|
||||
return models;
|
||||
}
|
||||
|
||||
private AiConversation createAiConversation(AiContextType uicontext, Dictionary<TableID, long[]> context, long modell_oid, AiDataContextType context_Type)
|
||||
protected virtual AiConversation createAiConversation(AiContextType uicontext, Dictionary<TableID, long[]> context, long modell_oid, AiDataContextType context_Type)
|
||||
{
|
||||
var current_user = UserRightHelper.GetLoggedInUserWithOid();
|
||||
var factory = new AiPromptFactory();
|
||||
@@ -282,7 +292,7 @@ namespace BeWo.Service.Plugins
|
||||
return conv;
|
||||
}
|
||||
|
||||
private AiConversationMessageDC[] sendNewMessage(AiConversation conv, string message, AiConfigDC config = null)
|
||||
protected virtual AiConversationMessageDC[] sendNewMessage(AiConversation conv, string message, AiConfigDC config = null)
|
||||
{
|
||||
// Hole Config
|
||||
if (config == null)
|
||||
@@ -324,7 +334,16 @@ namespace BeWo.Service.Plugins
|
||||
|
||||
// Send Request, wait for Response
|
||||
var dt_before_request = DateTime.Now;
|
||||
var response = ServiceFacade.ActiveAiClient.SendAiMessageRequest(payload, out var message2, out var model, out var duration);
|
||||
|
||||
ApiResponse<string> response;
|
||||
string message2, model;
|
||||
int? duration;
|
||||
if (config.SelectedModel.ModelSource == AiModelSource.openwebui)
|
||||
response = ServiceFacade.OpenWebApiClient.SendAiMessageRequest(payload, out message2, out model, out duration);
|
||||
else if (config.SelectedModel.ModelSource == AiModelSource.ollama)
|
||||
response = ServiceFacade.OllamaApiClient.SendAiMessageRequest(payload, out message2, out model, out duration);
|
||||
else
|
||||
throw new NotImplementedException();
|
||||
|
||||
if (!response.Success)
|
||||
{
|
||||
|
||||
@@ -1411,4 +1411,10 @@ namespace BS.Shared
|
||||
OrganisationSingle = 23,
|
||||
SupportConceptSingle = 24,
|
||||
}
|
||||
|
||||
public enum AiModelSource
|
||||
{
|
||||
openwebui,
|
||||
ollama
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -14,22 +15,28 @@ namespace BS.Shared.DataContracts.Feature.AI
|
||||
|
||||
}
|
||||
|
||||
public AiModelDC(string name, int value)
|
||||
public AiModelDC(AiModelSource modelSource, string name, int value)
|
||||
{
|
||||
ModelSource = modelSource;
|
||||
ModelName = name;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public string ModelName { get; set; }
|
||||
public int Value { get; set; }
|
||||
public AiModelSource ModelSource { get; set; }
|
||||
|
||||
public int CompareTo(AiModelDC other)
|
||||
public virtual int CompareTo(AiModelDC other)
|
||||
{
|
||||
if(other == null) return 1;
|
||||
if (other == null) return 1;
|
||||
|
||||
var comp = ModelName.CompareTo(other.ModelName);
|
||||
var comp = ModelSource.CompareTo(other.ModelSource);
|
||||
|
||||
if(comp != 0) return comp;
|
||||
if (comp != 0) return comp;
|
||||
|
||||
var comp1 = ModelName.CompareTo(other.ModelName);
|
||||
|
||||
if (comp1 != 0) return comp;
|
||||
|
||||
var comp2 = Value.CompareTo(other.Value);
|
||||
|
||||
@@ -38,10 +45,10 @@ namespace BS.Shared.DataContracts.Feature.AI
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is AiModelDC dc &&
|
||||
Oid == dc.Oid &&
|
||||
ModelName == dc.ModelName &&
|
||||
Value == dc.Value;
|
||||
return obj is AiModelDC ent &&
|
||||
ModelSource == ent.ModelSource &&
|
||||
ModelName == ent.ModelName &&
|
||||
Value == ent.Value;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
@@ -49,6 +56,7 @@ namespace BS.Shared.DataContracts.Feature.AI
|
||||
unchecked
|
||||
{
|
||||
var result = 0;
|
||||
result = (result * 397) ^ ModelSource.GetHashCode();
|
||||
result = (result * 397) ^ ModelName.GetHashCode();
|
||||
result = (result * 397) ^ Value.GetHashCode();
|
||||
return result;
|
||||
@@ -57,7 +65,7 @@ namespace BS.Shared.DataContracts.Feature.AI
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ModelName}";
|
||||
return $"{ModelName} ({ModelSource})";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user