temp 3? ich hab den Faden verloren. Ich habe mal eine Readme geschrieben hehe

This commit is contained in:
2025-08-05 11:55:48 +02:00
parent 959b8ca1c0
commit d9f8cdfb11
38 changed files with 824 additions and 129 deletions

View File

@@ -39,6 +39,7 @@
<Reference Include="System.IO.Pipelines, Version=9.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> <Reference Include="System.IO.Pipelines, Version=9.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Pipelines.9.0.2\lib\net462\System.IO.Pipelines.dll</HintPath> <HintPath>..\packages\System.IO.Pipelines.9.0.2\lib\net462\System.IO.Pipelines.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<Reference Include="System.Text.Encodings.Web, Version=9.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> <Reference Include="System.Text.Encodings.Web, Version=9.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encodings.Web.9.0.2\lib\net462\System.Text.Encodings.Web.dll</HintPath> <HintPath>..\packages\System.Text.Encodings.Web.9.0.2\lib\net462\System.Text.Encodings.Web.dll</HintPath>
</Reference> </Reference>
@@ -92,6 +93,10 @@
<Compile Include="Context\Summary\ServiceRecordNavigationContextSummary.cs" /> <Compile Include="Context\Summary\ServiceRecordNavigationContextSummary.cs" />
<Compile Include="Context\Summary\SupportConceptDetailContextSummary.cs" /> <Compile Include="Context\Summary\SupportConceptDetailContextSummary.cs" />
<Compile Include="Context\Summary\SupportConceptNavigationContextSummary.cs" /> <Compile Include="Context\Summary\SupportConceptNavigationContextSummary.cs" />
<Compile Include="Facade\DefaultErrorExtractor.cs" />
<Compile Include="Facade\LLM\BaseLLMApiClient.cs" />
<Compile Include="Facade\LLM\OllamaApiClient.cs" />
<Compile Include="Facade\LLM\OpenWebApiClient.cs" />
<Compile Include="Prompt\Core\AiUtils.cs" /> <Compile Include="Prompt\Core\AiUtils.cs" />
<Compile Include="Prompt\Factories\AiPromptFactory.cs" /> <Compile Include="Prompt\Factories\AiPromptFactory.cs" />
<Compile Include="Prompt\Models\AiConversationContext.cs" /> <Compile Include="Prompt\Models\AiConversationContext.cs" />
@@ -111,6 +116,10 @@
<Project>{B0D73E3D-4AE7-4024-93A6-DB1F46D7CCEE}</Project> <Project>{B0D73E3D-4AE7-4024-93A6-DB1F46D7CCEE}</Project>
<Name>Data</Name> <Name>Data</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\Server\ApiFacade\ApiFacade.csproj">
<Project>{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}</Project>
<Name>ApiFacade</Name>
</ProjectReference>
<ProjectReference Include="..\ServiceUtils\ServiceUtils.csproj"> <ProjectReference Include="..\ServiceUtils\ServiceUtils.csproj">
<Project>{EC2349FB-7FE0-4AD1-B28B-A7A27AF80A57}</Project> <Project>{EC2349FB-7FE0-4AD1-B28B-A7A27AF80A57}</Project>
<Name>ServiceUtils</Name> <Name>ServiceUtils</Name>

View File

@@ -15,11 +15,12 @@ namespace AICore.Context.SummaryParser
public class CsvContextSummaryParser : BaseContextSummaryParser public class CsvContextSummaryParser : BaseContextSummaryParser
{ {
private string _Delimiter; private string _Delimiter;
private bool _StrictEscapeCsvField;
public CsvContextSummaryParser() : this(",") { } public CsvContextSummaryParser(string delimiter = ",", bool strictEscapeCsvField = false)
public CsvContextSummaryParser(string delimiter)
{ {
_Delimiter = delimiter; _Delimiter = delimiter;
_StrictEscapeCsvField = strictEscapeCsvField;
} }
public override string Parse(AiContextType uicontext, BaseContextSummary context) public override string Parse(AiContextType uicontext, BaseContextSummary context)
@@ -111,14 +112,21 @@ namespace AICore.Context.SummaryParser
if (string.IsNullOrEmpty(field)) if (string.IsNullOrEmpty(field))
return string.Empty; return string.Empty;
// Wenn das Feld Kommas, Anführungszeichen oder Zeilumbrüche enthält, if (_StrictEscapeCsvField)
// muss es in Anführungszeichen gesetzt werden
if (field.Contains(_Delimiter) || field.Contains("\"") || field.Contains("\n") || field.Contains("\r"))
{ {
// Anführungszeichen im Feld verdoppeln
field = field.Replace("\"", "\"\"");
return $"\"{field}\""; return $"\"{field}\"";
} }
else
{
// Wenn das Feld Kommas, Anführungszeichen oder Zeilumbrüche enthält,
// muss es in Anführungszeichen gesetzt werden
if (field.Contains(_Delimiter) || field.Contains("\"") || field.Contains("\n") || field.Contains("\r"))
{
// Anführungszeichen im Feld verdoppeln
field = field.Replace("\"", "\"\"");
return $"\"{field}\"";
}
}
return field; return field;
} }

View File

@@ -6,7 +6,7 @@ using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace BeWo.Service.Api.ErrorExtractor namespace AICore.Facade
{ {
public class DefaultErrorExtractor : IApiErrorExtractor public class DefaultErrorExtractor : IApiErrorExtractor
{ {

View File

@@ -0,0 +1,30 @@
using BeWo.Data.Entities;
using BeWo.ServiceUtils.Core;
using BS.Shared.DataContracts.Feature.AI;
using BS.Shared.DataContracts;
using BS.Shared.Interface;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.Json;
namespace AICore.Facade.LLM
{
public abstract class BaseLLMApiClient
{
public string BaseUrl { get; set; }
public string ApiKey { get; set; }
protected BaseLLMApiClient(string base_url, string api_key)
{
base_url = BaseUrl;
ApiKey = api_key;
}
public abstract ApiResponse<IEnumerable<AiModel>> GetAiModelle();
public abstract ApiResponse<string> SendAiMessageRequest(dynamic payload, out string message, out string model, out int? duration);
}
}

View File

@@ -0,0 +1,124 @@
using BeWo.Data.Entities;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Feature.AI;
using BS.Shared.Extensions;
using BS.Shared.Interface;
using System.Collections.Generic;
using System;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using BeWo.Server.ApiFacade.Core;
namespace AICore.Facade.LLM
{
public class OllamaApiClient : BaseLLMApiClient
{
private protected readonly HttpClientFacade _GetClientFacade;
private protected readonly JsonHttpClientFacade _PostClientFacade;
private protected readonly IApiErrorExtractor _ErrorExtractor;
public OllamaApiClient(string base_url, string api_key) : base(base_url, api_key)
{
var authorization = $"Bearer {api_key}";
_GetClientFacade = new HttpClientFacade(base_url);
_GetClientFacade.SetToken(authorization);
_PostClientFacade = new JsonHttpClientFacade(base_url);
_PostClientFacade.SetToken(authorization);
_PostClientFacade.Timeout = TimeSpan.FromSeconds(300);
_ErrorExtractor = new DefaultErrorExtractor();
try
{
var addresses = Dns.GetHostAddresses("w2.ownchat.de");
foreach (var addr in addresses)
Console.WriteLine(addr);
}
catch (SocketException ex)
{
Console.WriteLine($"DNS resolution failed: {ex.Message}");
}
}
public override ApiResponse<IEnumerable<AiModel>> GetAiModelle()
{
var models = new List<AiModelDC>();
var response_format = new
{
models = new[]
{
new
{
name = "",
model = ""
}
}
};
var response = _GetClientFacade.GetAnonymousTypeAsync("api/ollama/models", response_format, _ErrorExtractor).GetAwaiter().GetResult();
if (!response.Success)
{
throw new NotImplementedException();
}
var data = response.Data.models.Select(x => new AiModel(x.name, 0));
return ApiResponse<IEnumerable<AiModel>>.SuccessResponse(data);
}
public override ApiResponse<string> SendAiMessageRequest(dynamic payload, out string message, out string model, out int? duration)
{
message = null;
duration = null;
model = null;
_PostClientFacade.JsonObject = payload;
var response_format = new
{
id = string.Empty,
model = string.Empty,
message = new
{
content = string.Empty,
role = string.Empty
},
done_reason = "stop",
done = true,
total_duration = 1316754573L,
load_duration = 31739136L,
prompt_eval_count = 22L,
prompt_eval_duration = 2132887L,
eval_count = 66L,
eval_duration = 1282438235L
};
var response = _PostClientFacade.GetAnonymousTypeAsync("api/ollama/chat/completions", response_format, _ErrorExtractor).GetAwaiter().GetResult();
if (!response.Success)
return response.Copy<string>();
var json = response.GetResponseData();
if (json.message is object && !string.IsNullOrEmpty(json.message.content))
{
var total_ns = json.total_duration;
var total_ms = total_ns / 1000000;
duration = (int)total_ms;
model = json.model;
var assi_msg = BS.Shared.Core.Utils.ConvertToISO88591(json.message.content);
message = assi_msg;
return ApiResponse<string>.SuccessResponse(assi_msg);
}
return null;
}
}
}

View File

@@ -1,36 +1,23 @@
using BeWo.Data.Entities; using BeWo.Data.Entities;
using BeWo.Service.Api.ErrorExtractor; using BeWo.Server.ApiFacade.Core;
using BeWo.Service.Core;
using BeWo.Service.DCEntityMapper;
using BS.Shared.Core;
using BS.Shared.Core.Facade;
using BS.Shared.DataContracts; using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Feature.AI; using BS.Shared.DataContracts.Feature.AI;
using BS.Shared.Exceptions;
using BS.Shared.Extensions; using BS.Shared.Extensions;
using BS.Shared.Interface; using BS.Shared.Interface;
using DevExpress.DataProcessing.InMemoryDataProcessor;
using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Configuration;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Text.Json;
using System.Text;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using static DevExpress.Xpo.Helpers.AssociatedCollectionCriteriaHelper;
namespace BeWo.Service.ServiceProxy namespace AICore.Facade.LLM
{ {
public class OpenWebApiClient public class OpenWebApiClient : BaseLLMApiClient
{ {
private readonly HttpClientFacade _GetClientFacade; private protected readonly HttpClientFacade _GetClientFacade;
private readonly JsonHttpClientFacade _PostClientFacade; private protected readonly JsonHttpClientFacade _PostClientFacade;
private readonly IApiErrorExtractor _ErrorExtractor; private protected readonly IApiErrorExtractor _ErrorExtractor;
public OpenWebApiClient() : this(MergedConfig.GetSetting("OpenWebUIUrl"), MergedConfig.GetSetting("OpenWebUIKey")) { }
public OpenWebApiClient(string base_url, string api_key) public OpenWebApiClient(string base_url, string api_key)
{ {
var authorization = $"Bearer {api_key}"; var authorization = $"Bearer {api_key}";
@@ -42,13 +29,21 @@ namespace BeWo.Service.ServiceProxy
_ErrorExtractor = new DefaultErrorExtractor(); _ErrorExtractor = new DefaultErrorExtractor();
} }
public ApiResponse<IEnumerable<AiModel>> GetAiModelle() public override ApiResponse<IEnumerable<AiModel>> GetAiModelle()
{ {
var models = new List<AiModelDC>(); var models = new List<AiModelDC>();
var response_format = new var response_format = new
{ {
data = models data = new[]
{
new
{
id = "",
name = ""
}
}
}; };
var response = _GetClientFacade.GetAnonymousTypeAsync("api/models", response_format, _ErrorExtractor).GetAwaiter().GetResult(); var response = _GetClientFacade.GetAnonymousTypeAsync("api/models", response_format, _ErrorExtractor).GetAwaiter().GetResult();
@@ -58,18 +53,18 @@ namespace BeWo.Service.ServiceProxy
throw new NotImplementedException(); throw new NotImplementedException();
} }
var data = MapperFactory.AiModel.MapToNewEntities(response.Data.data); var data = response.Data.data.Select(x => new AiModel(x.name, 0));
return ApiResponse<IEnumerable<AiModel>>.SuccessResponse(data); return ApiResponse<IEnumerable<AiModel>>.SuccessResponse(data);
} }
public ApiResponse<string> SendAiMessageRequest(dynamic payload, out string message, out string model, out int? duration) public override ApiResponse<string> SendAiMessageRequest(dynamic payload, out string message, out string model, out int? duration)
{ {
message = null; message = null;
duration = null; duration = null;
model = null; model = null;
var sub_url = "api/chat/completions"; _PostClientFacade.JsonObject = payload;
var response_format = new var response_format = new
{ {
@@ -94,20 +89,7 @@ namespace BeWo.Service.ServiceProxy
} }
}; };
_PostClientFacade.JsonObject = payload; var response = _PostClientFacade.GetAnonymousTypeAsync("api/chat/completions", response_format, _ErrorExtractor).GetAwaiter().GetResult();
if (MergedConfig.GetSetting("AiServiceLastRequestEnabled") is string str && bool.TryParse(str, out bool b) && b)
{
var path = MergedConfig.GetSetting("AiServiceLastRequestFilePath");
if (Directory.GetParent(path) == null)
throw new ArgumentException("AiServiceLastRequestFilePath ungültig");
var payload_ser = JsonConvert.SerializeObject(_PostClientFacade.JsonObject, Formatting.Indented);
File.WriteAllText(path, payload_ser);
}
var response = _PostClientFacade.GetAnonymousTypeAsync(sub_url, response_format, _ErrorExtractor).GetAwaiter().GetResult();
if (!response.Success) if (!response.Success)
return response.Copy<string>(); return response.Copy<string>();
@@ -120,7 +102,7 @@ namespace BeWo.Service.ServiceProxy
{ {
var total_ns = json.usage.total_duration; var total_ns = json.usage.total_duration;
var total_ms = total_ns / 1000000; var total_ms = total_ns / 1000000;
duration = (int)total_ms; duration = (int)total_ms;
model = json.model; model = json.model;

View File

@@ -60,6 +60,10 @@ namespace AICore.Prompt.Factories
return new CsvContextSummaryParser(); return new CsvContextSummaryParser();
case AiDataContextType.tsv: case AiDataContextType.tsv:
return new CsvContextSummaryParser("\t"); return new CsvContextSummaryParser("\t");
case AiDataContextType.csv2:
return new CsvContextSummaryParser(";", true);
case AiDataContextType.tsv2:
return new CsvContextSummaryParser("\t", true);
default: default:
break; break;
} }

View File

@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{68C1F8EA-7828-4E46-8F04-91105C55860E}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AiCoreUnitTest</RootNamespace>
<AssemblyName>AiCoreUnitTest</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="OllamaFacadeTest.cs" />
<Compile Include="OpenWebUIFacadeTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AICore\AICore.csproj">
<Project>{69D70CA9-0DF9-419E-BFAF-F4539F129BD9}</Project>
<Name>AICore</Name>
</ProjectReference>
<ProjectReference Include="..\Data\Data.csproj">
<Project>{B0D73E3D-4AE7-4024-93A6-DB1F46D7CCEE}</Project>
<Name>Data</Name>
</ProjectReference>
<ProjectReference Include="..\Shared\Shared.csproj">
<Project>{2F50B83D-A3F0-4EC4-979A-3F9B7E3D8ED4}</Project>
<Name>Shared</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props'))" />
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets'))" />
</Target>
<Import Project="..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets')" />
</Project>

View File

@@ -0,0 +1,34 @@
using AICore.Facade.LLM;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Net;
namespace AiCoreUnitTest
{
[TestClass]
public class OllamaFacadeTest
{
public string OllamaUrl { get; set; }
public string OllamaKey { get; set; }
[TestInitialize]
public void TestInitialize()
{
OllamaUrl = "https://w2.owchat.de";
OllamaKey = "mu9ZPuUXJ4aVGLU1WL2RfPCeSMRmJREwyjVJBP7bHfSz8quZRqN7e7UwnwCDi8GZ";
}
public OllamaApiClient GetOllamaApiClient()
=> new OllamaApiClient(OllamaUrl, OllamaKey);
[TestMethod]
public void GetModels()
{
var client = GetOllamaApiClient();
var models = client.GetAiModelle();
Assert.IsNotNull(models);
}
}
}

View File

@@ -0,0 +1,34 @@
using AICore.Facade.LLM;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Net;
namespace AiCoreUnitTest
{
[TestClass]
public class OpenWebUIFacadeTest
{
public string OpenWebUIUrl { get; set; }
public string OpenWebUIKey { get; set; }
[TestInitialize]
public void TestInitialize()
{
OpenWebUIUrl = "https://owui1.ownsoft.de/";
OpenWebUIKey = "sk-7f5d8c418630448dbe31ab1c7e8b100a";
}
public OpenWebApiClient GetOpenWebApiClient()
=> new OpenWebApiClient(OpenWebUIUrl, OpenWebUIKey);
[TestMethod]
public void GetModels()
{
var client = GetOpenWebApiClient();
var models = client.GetAiModelle();
Assert.IsNotNull(models);
}
}
}

View File

@@ -0,0 +1,20 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("AiCoreUnitTest")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AiCoreUnitTest")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("68c1f8ea-7828-4e46-8f04-91105c55860e")]
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="MSTest.TestAdapter" version="2.2.10" targetFramework="net472" />
<package id="MSTest.TestFramework" version="2.2.10" targetFramework="net472" />
</packages>

View File

@@ -59,7 +59,7 @@ namespace BeWo
public static string ShortVersion = "3.26"; public static string ShortVersion = "3.26";
public static string Version = "Version 3.26 - 1.2 Test"; public static string Version = "Version 3.26 - 1.2.1 Test";
public static int RenderTier = 0; public static int RenderTier = 0;
public static bool IsInDesignMode = DesignerProperties.GetIsInDesignMode(new DependencyObject()); public static bool IsInDesignMode = DesignerProperties.GetIsInDesignMode(new DependencyObject());

View File

@@ -6,11 +6,11 @@
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors" xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
xmlns:listviewmodel="clr-namespace:BeWo.ViewModel.ListViewModel" xmlns:listviewmodel="clr-namespace:BeWo.ViewModel.ListViewModel"
xmlns:local="clr-namespace:BeWo.View.Detail.AI" xmlns:local="clr-namespace:BeWo.View.Detail.AI"
xmlns:shared="clr-namespace:BS.Shared;assembly=BS.Shared"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:shared="clr-namespace:BS.Shared;assembly=BS.Shared"
xmlns:vmv="clr-namespace:BeWo.ViewModel.View" xmlns:vmv="clr-namespace:BeWo.ViewModel.View"
d:DataContext="{d:DesignInstance Type=vmv:AiConversationChatViewModel, d:DataContext="{d:DesignInstance Type=vmv:AiConversationChatViewModel,
IsDesignTimeCreatable=True}" IsDesignTimeCreatable=True}"
mc:Ignorable="d"> mc:Ignorable="d">
<UserControl.Resources> <UserControl.Resources>
<ResourceDictionary> <ResourceDictionary>
@@ -25,7 +25,7 @@
<Setter Property="SmallChange" Value="0.01" /> <Setter Property="SmallChange" Value="0.01" />
<Setter Property="IsMoveToPointEnabled" Value="True" /> <Setter Property="IsMoveToPointEnabled" Value="True" />
</Style> </Style>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource PopupWhiteLabel}"/> <Style BasedOn="{StaticResource PopupWhiteLabel}" TargetType="{x:Type Label}" />
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>
@@ -91,14 +91,19 @@
IsEnabled="False" IsEnabled="False"
Style="{StaticResource TextEditNumber}" /> Style="{StaticResource TextEditNumber}" />
<Label Grid.Row="4"> <Label Grid.Row="4" VerticalAlignment="Top">
Datenformat Datenformat
</Label> </Label>
<StackPanel Grid.Row="4" Orientation="Horizontal" <StackPanel Grid.Row="4" Grid.Column="2">
Grid.Column="2"> <StackPanel Orientation="Horizontal">
<RadioButton IsChecked="{Binding Config.Context_Type, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static shared:AiDataContextType.json}}">json</RadioButton> <RadioButton IsChecked="{Binding Config.Context_Type, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static shared:AiDataContextType.json}}">json</RadioButton>
<RadioButton IsChecked="{Binding Config.Context_Type, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static shared:AiDataContextType.csv}}">csv</RadioButton> <RadioButton IsChecked="{Binding Config.Context_Type, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static shared:AiDataContextType.csv}}">csv</RadioButton>
<RadioButton IsChecked="{Binding Config.Context_Type, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static shared:AiDataContextType.tsv}}">tsv</RadioButton> <RadioButton IsChecked="{Binding Config.Context_Type, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static shared:AiDataContextType.tsv}}">tsv</RadioButton>
</StackPanel>
<StackPanel Orientation="Horizontal">
<RadioButton IsChecked="{Binding Config.Context_Type, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static shared:AiDataContextType.csv2}}">csv2</RadioButton>
<RadioButton IsChecked="{Binding Config.Context_Type, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static shared:AiDataContextType.tsv2}}">tsv2</RadioButton>
</StackPanel>
</StackPanel> </StackPanel>
</Grid> </Grid>
</Grid> </Grid>

View File

@@ -50,6 +50,7 @@
<RowDefinition Height="auto" /> <RowDefinition Height="auto" />
<RowDefinition Height="auto" /> <RowDefinition Height="auto" />
<RowDefinition Height="auto" /> <RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock <TextBlock
FontSize="14" FontSize="14"
@@ -84,6 +85,12 @@
Foreground="{DynamicResource TextForegroundSecondary}" Foreground="{DynamicResource TextForegroundSecondary}"
Style="{StaticResource TextBlockStyle}" Style="{StaticResource TextBlockStyle}"
Text="{Binding Updated, StringFormat=Aktualisiert: {0:dd.MM.yy HH:mm}}" /> Text="{Binding Updated, StringFormat=Aktualisiert: {0:dd.MM.yy HH:mm}}" />
<TextBlock
Grid.Row="3"
FontSize="11"
Foreground="{DynamicResource TextForegroundSecondary}"
Style="{StaticResource TextBlockStyle}"
Text="{Binding Context_Type, StringFormat=Format: {0}}" />
<!--<TextBlock <!--<TextBlock
Grid.Row="2" Grid.Row="2"
FontSize="10" FontSize="10"

View File

@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.12.35707.178 d17.12 VisualStudioVersion = 17.12.35707.178
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{E7543C39-A44C-40C9-82C9-E7FAA2D9A852}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{E7543C39-A44C-40C9-82C9-E7FAA2D9A852}"
EndProject EndProject
@@ -49,6 +49,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AICore", "AICore\AICore.csp
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceUtils", "ServiceUtils\ServiceUtils.csproj", "{EC2349FB-7FE0-4AD1-B28B-A7A27AF80A57}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceUtils", "ServiceUtils\ServiceUtils.csproj", "{EC2349FB-7FE0-4AD1-B28B-A7A27AF80A57}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AI", "AI", "{084C391D-FCE1-4984-87FA-F8F9CFCC6A4F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AiCoreUnitTest", "AiCoreUnitTest\AiCoreUnitTest.csproj", "{68C1F8EA-7828-4E46-8F04-91105C55860E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiFacade", "Server\ApiFacade\ApiFacade.csproj", "{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|.NET = Debug|.NET Debug|.NET = Debug|.NET
@@ -219,6 +225,30 @@ Global
{EC2349FB-7FE0-4AD1-B28B-A7A27AF80A57}.Release|Any CPU.Build.0 = Release|Any CPU {EC2349FB-7FE0-4AD1-B28B-A7A27AF80A57}.Release|Any CPU.Build.0 = Release|Any CPU
{EC2349FB-7FE0-4AD1-B28B-A7A27AF80A57}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {EC2349FB-7FE0-4AD1-B28B-A7A27AF80A57}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{EC2349FB-7FE0-4AD1-B28B-A7A27AF80A57}.Release|Mixed Platforms.Build.0 = Release|Any CPU {EC2349FB-7FE0-4AD1-B28B-A7A27AF80A57}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{68C1F8EA-7828-4E46-8F04-91105C55860E}.Debug|.NET.ActiveCfg = Debug|Any CPU
{68C1F8EA-7828-4E46-8F04-91105C55860E}.Debug|.NET.Build.0 = Debug|Any CPU
{68C1F8EA-7828-4E46-8F04-91105C55860E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{68C1F8EA-7828-4E46-8F04-91105C55860E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{68C1F8EA-7828-4E46-8F04-91105C55860E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{68C1F8EA-7828-4E46-8F04-91105C55860E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{68C1F8EA-7828-4E46-8F04-91105C55860E}.Release|.NET.ActiveCfg = Release|Any CPU
{68C1F8EA-7828-4E46-8F04-91105C55860E}.Release|.NET.Build.0 = Release|Any CPU
{68C1F8EA-7828-4E46-8F04-91105C55860E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{68C1F8EA-7828-4E46-8F04-91105C55860E}.Release|Any CPU.Build.0 = Release|Any CPU
{68C1F8EA-7828-4E46-8F04-91105C55860E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{68C1F8EA-7828-4E46-8F04-91105C55860E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}.Debug|.NET.ActiveCfg = Debug|Any CPU
{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}.Debug|.NET.Build.0 = Debug|Any CPU
{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}.Release|.NET.ActiveCfg = Release|Any CPU
{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}.Release|.NET.Build.0 = Release|Any CPU
{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}.Release|Any CPU.Build.0 = Release|Any CPU
{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -240,6 +270,9 @@ Global
{830D2912-108B-4946-A3BE-CE4ECD50819F} = {FEB0336B-F053-40B6-92DD-7DE56AB9408A} {830D2912-108B-4946-A3BE-CE4ECD50819F} = {FEB0336B-F053-40B6-92DD-7DE56AB9408A}
{69D70CA9-0DF9-419E-BFAF-F4539F129BD9} = {830D2912-108B-4946-A3BE-CE4ECD50819F} {69D70CA9-0DF9-419E-BFAF-F4539F129BD9} = {830D2912-108B-4946-A3BE-CE4ECD50819F}
{EC2349FB-7FE0-4AD1-B28B-A7A27AF80A57} = {FEB0336B-F053-40B6-92DD-7DE56AB9408A} {EC2349FB-7FE0-4AD1-B28B-A7A27AF80A57} = {FEB0336B-F053-40B6-92DD-7DE56AB9408A}
{084C391D-FCE1-4984-87FA-F8F9CFCC6A4F} = {CCD6B644-49E7-4A11-BD8F-607088A4AC83}
{68C1F8EA-7828-4E46-8F04-91105C55860E} = {084C391D-FCE1-4984-87FA-F8F9CFCC6A4F}
{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7} = {FEB0336B-F053-40B6-92DD-7DE56AB9408A}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5352BE53-F2FD-442F-85A8-4157599AA153} SolutionGuid = {5352BE53-F2FD-442F-85A8-4157599AA153}

View File

@@ -1,5 +1,5 @@
using BS.Shared; using BS.Shared;
using BS.Shared.DataContracts.Feature.AI;
using System; using System;
namespace BeWo.Data.Entities namespace BeWo.Data.Entities
@@ -11,7 +11,33 @@ namespace BeWo.Data.Entities
_Tid = TableID.AiModel; _Tid = TableID.AiModel;
} }
public AiModel(string modelName, int value) : this()
{
ModelName = modelName;
Value = value;
}
public virtual string ModelName { get; set; } public virtual string ModelName { get; set; }
public virtual int Value { get; set; } public virtual int Value { get; set; }
public virtual int CompareTo(AiModel other)
{
if (other == null) return 1;
var comp = ModelName.CompareTo(other.ModelName);
if (comp != 0) return comp;
var comp2 = Value.CompareTo(other.Value);
return comp2;
}
public override bool Equals(object obj)
{
return obj is AiModel ent &&
ModelName == ent.ModelName &&
Value == ent.Value;
}
} }
} }

View File

@@ -0,0 +1,5 @@
{
"AiEnabled": true,
"AiTestPhase": true,
"DefaultModel": "llama3"
}

View File

@@ -432,6 +432,7 @@
<Content Include="Multitenancy\debugMsSQL.config" /> <Content Include="Multitenancy\debugMsSQL.config" />
<Content Include="Multitenancy\debugMySQL.config" /> <Content Include="Multitenancy\debugMySQL.config" />
<Content Include="Multitenancy\demo.config" /> <Content Include="Multitenancy\demo.config" />
<None Include="Config\ai.config.json" />
<None Include="Properties\PublishProfiles\BeWo2.0.pubxml" /> <None Include="Properties\PublishProfiles\BeWo2.0.pubxml" />
<Content Include="Scripts\german-datepicker.js" /> <Content Include="Scripts\german-datepicker.js" />
<None Include="Scripts\jquery-3.7.1.intellisense.js" /> <None Include="Scripts\jquery-3.7.1.intellisense.js" />

View File

@@ -307,7 +307,8 @@
<add key="SendMailModuleGkvSender" value="noreply@bewoplaner.de" /> <add key="SendMailModuleGkvSender" value="noreply@bewoplaner.de" />
<add key="SendMailModuleGkvReceiver" value="dakota.exchange@ownsoft.de" /> <add key="SendMailModuleGkvReceiver" value="dakota.exchange@ownsoft.de" />
<add key="OpenWebUIUrl" value="https://owui1.ownsoft.de/" /> <add key="OpenWebUIUrl" value="https://owui1.ownsoft.de" />
<add key="OllamaUrl" value="https://w2.ownchat.de" />
<add key="AiSystemPromptPath" value="C:\BeWoPlaner\AI\systemPrompts\customSystemPrompt.txt" /> <add key="AiSystemPromptPath" value="C:\BeWoPlaner\AI\systemPrompts\customSystemPrompt.txt" />
<add key="AiServiceLogFilePath" value="C:\BeWoPlaner\logs2\server\aiservice.log.txt" /> <add key="AiServiceLogFilePath" value="C:\BeWoPlaner\logs2\server\aiservice.log.txt" />
<add key="AiServiceLastRequestEnabled" value="true" /> <add key="AiServiceLastRequestEnabled" value="true" />

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4B2F3959-3CDA-4514-83A2-FA3C24E57BB7}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>BeWo.Server.ApiFacade</RootNamespace>
<AssemblyName>BeWo.Server.ApiFacade</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Core\HttpClientFacade.cs" />
<Compile Include="Core\JsonHttpClientFacade.cs" />
<Compile Include="Core\WebClientFacade.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj">
<Project>{2F50B83D-A3F0-4EC4-979A-3F9B7E3D8ED4}</Project>
<Name>Shared</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="README.txt" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -1,7 +1,7 @@
using BS.Shared.DataContracts; using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.Exceptions; using BS.Shared.Exceptions;
using BS.Shared.Interface; using BS.Shared.Interface;
using DevExpress.Mvvm.POCO;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -9,46 +9,48 @@ using System.Diagnostics.Eventing.Reader;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.Security;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace BS.Shared.Core.Facade namespace BeWo.Server.ApiFacade.Core
{ {
public class HttpClientFacade public class HttpClientFacade
{ {
public string Base_Url { get; set; } public bool DirectConnect { get; private set; }
public string Base_Url { get; private set; }
public HttpMethod Method { get; set; } = HttpMethod.Get; public HttpMethod Method { get; set; } = HttpMethod.Get;
public Dictionary<string, string> Headers { get; set; } = new Dictionary<string, string>(); public Dictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
public Dictionary<string, string> Parameters { get; set; } = new Dictionary<string, string>(); public Dictionary<string, string> Parameters { get; set; } = new Dictionary<string, string>();
public string ContentType { get; set; } = "application/x-www-form-urlencoded"; public string ContentType { get; set; } = "application/x-www-form-urlencoded";
public Encoding Encoding { get; set; } = Encoding.UTF8; public Encoding Encoding { get; private set; } = Encoding.UTF8;
public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(30); public TimeSpan Timeout { get; private set; } = TimeSpan.FromSeconds(30);
public HttpClientFacade(string base_url) public HttpClientFacade(string base_url, string api_key, bool directConntect = true)
{ {
if (string.IsNullOrEmpty(base_url)) if (string.IsNullOrEmpty(base_url))
throw new ArgumentNullException("HttpClient: base_url is missing"); throw new ArgumentNullException("HttpClient: base_url is missing");
Base_Url = base_url; if (string.IsNullOrWhiteSpace(api_key))
}
public void SetToken(string token)
{
if (string.IsNullOrWhiteSpace(token))
throw new ArgumentNullException("HttpClient: token is missing"); throw new ArgumentNullException("HttpClient: token is missing");
var key = nameof(HttpRequestHeader.Authorization); Base_Url = base_url;
SetToken(api_key);
if (Headers.ContainsKey(key)) DirectConnect = directConntect;
{
Headers[key] = token;
}
else
{
Headers.Add(key, token);
}
} }
/// <summary>
/// Führt einen Request aus, erwartet einen komplexen Datentyp: Schaue Verweise für Beispiele.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="method"></param>
/// <param name="anonymousType"></param>
/// <param name="extractor"></param>
/// <returns></returns>
public virtual async Task<ApiResponse<T>> GetAnonymousTypeAsync<T>(string method, T anonymousType, IApiErrorExtractor extractor) public virtual async Task<ApiResponse<T>> GetAnonymousTypeAsync<T>(string method, T anonymousType, IApiErrorExtractor extractor)
{ {
var http_response = await getResponseAsync(method).ConfigureAwait(false); var http_response = await getResponseAsync(method).ConfigureAwait(false);
@@ -63,6 +65,15 @@ namespace BS.Shared.Core.Facade
return parse(() => JsonConvert.DeserializeAnonymousType<T>(json, anonymousType), json, extractor); return parse(() => JsonConvert.DeserializeAnonymousType<T>(json, anonymousType), json, extractor);
} }
/// <summary>
/// Führt einen Request aus, erwartet einen einfachen Datentyp wie: string, int, decimal, byte[] -
/// Liste kann gerne erweitert werden
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="method"></param>
/// <param name="extractor"></param>
/// <returns></returns>
/// <exception cref="BeWoInvalidOperationException"></exception>
public virtual async Task<ApiResponse<T>> GetAsync<T>(string method, IApiErrorExtractor extractor) public virtual async Task<ApiResponse<T>> GetAsync<T>(string method, IApiErrorExtractor extractor)
{ {
var http_response = await getResponseAsync(method).ConfigureAwait(false); var http_response = await getResponseAsync(method).ConfigureAwait(false);
@@ -80,15 +91,15 @@ namespace BS.Shared.Core.Facade
{ {
result = content; result = content;
} }
else if(type == typeof(int)) else if (type == typeof(int))
{ {
result = int.Parse(content); result = int.Parse(content);
} }
else if(type == typeof(decimal)) else if (type == typeof(decimal))
{ {
result = decimal.Parse(content); result = decimal.Parse(content);
} }
else if(type == typeof(byte[])) else if (type == typeof(byte[]))
{ {
result = await http_response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); result = await http_response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
} }
@@ -96,15 +107,35 @@ namespace BS.Shared.Core.Facade
{ {
throw new BeWoInvalidOperationException(AppError.UnsupportedType(typeof(T))); throw new BeWoInvalidOperationException(AppError.UnsupportedType(typeof(T)));
} }
return parse(() => (T)result, content, extractor); return parse(() => (T)result, content, extractor);
} }
private static bool ServerCertificateCustomValidation(HttpRequestMessage requestMessage, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslErrors)
{
// It is possible to inspect the certificate provided by the server.
Console.WriteLine($"Requested URI: {requestMessage.RequestUri}");
Console.WriteLine($"Effective date: {certificate?.GetEffectiveDateString()}");
Console.WriteLine($"Exp date: {certificate?.GetExpirationDateString()}");
Console.WriteLine($"Issuer: {certificate?.Issuer}");
Console.WriteLine($"Subject: {certificate?.Subject}");
// Based on the custom logic it is possible to decide whether the client considers certificate valid or not
Console.WriteLine($"Errors: {sslErrors}");
return sslErrors == SslPolicyErrors.None;
}
private protected virtual async Task<HttpResponseMessage> getResponseAsync(string method) private protected virtual async Task<HttpResponseMessage> getResponseAsync(string method)
{ {
using (var client = new HttpClient { Timeout = Timeout }) var handler = new HttpClientHandler
{ {
var requestUri = Utilities.WebUtils.CombineUrl(Base_Url, method); ServerCertificateCustomValidationCallback = ServerCertificateCustomValidation,
SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls,
};
using (var client = new HttpClient(handler) { Timeout = Timeout })
{
var requestUri = BS.Shared.Core.Utilities.WebUtils.CombineUrl(Base_Url, method);
if (Method == HttpMethod.Get && Parameters.Count > 0) if (Method == HttpMethod.Get && Parameters.Count > 0)
{ {
@@ -114,9 +145,7 @@ namespace BS.Shared.Core.Facade
using (var request = new HttpRequestMessage(Method, requestUri)) using (var request = new HttpRequestMessage(Method, requestUri))
{ {
// Add headers await checkForDirect(request).ConfigureAwait(false);
foreach (var header in Headers)
request.Headers.TryAddWithoutValidation(header.Key, header.Value);
// Add body if POST or PUT // Add body if POST or PUT
if (Method == HttpMethod.Post || Method == HttpMethod.Put) if (Method == HttpMethod.Post || Method == HttpMethod.Put)
@@ -132,6 +161,55 @@ namespace BS.Shared.Core.Facade
} }
} }
private protected async Task checkForDirect(HttpRequestMessage request)
{
if (!DirectConnect || request.RequestUri is null)
return;
var host = request.RequestUri.DnsSafeHost;
var isSslSession = request.RequestUri.ToString().StartsWith("https://");
try
{
// DNS-Auflösung für den Hostnamen durchführen
var ipAddresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false);
// Erste verfügbare IP-Adresse verwenden (IPv4 bevorzugen)
var targetIp = ipAddresses.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork)
?? ipAddresses.FirstOrDefault();
if (targetIp != null)
{
request.RequestUri = new Uri($"{(isSslSession ? "https://" : "http://")}{targetIp}{request.RequestUri.PathAndQuery}");
request.Headers.Host = host;
}
}
catch (Exception ex)
{
// Fallback: Original URI beibehalten bei DNS-Fehlern
// Optional: Logging des Fehlers
Console.WriteLine($"DNS resolution failed for {host}: {ex.Message}");
}
// Add headers
foreach (var header in Headers)
request.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
private void SetToken(string token)
{
var key = nameof(HttpRequestHeader.Authorization);
if (Headers.ContainsKey(key))
{
Headers[key] = token;
}
else
{
Headers.Add(key, token);
}
}
private ApiResponse<T> parse<T>(Func<T> func, string json, IApiErrorExtractor errorExtractor) private ApiResponse<T> parse<T>(Func<T> func, string json, IApiErrorExtractor errorExtractor)
{ {
try try

View File

@@ -1,21 +1,19 @@
using BS.Shared.DataContracts.Feature.AI; using System;
using BS.Shared.DataContracts;
using Newtonsoft.Json;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.IO; using System.IO;
using Newtonsoft.Json;
namespace BS.Shared.Core.Facade namespace BeWo.Server.ApiFacade.Core
{ {
public class JsonHttpClientFacade : HttpClientFacade public class JsonHttpClientFacade : HttpClientFacade
{ {
public object JsonObject { get; set; } public object JsonObject { get; set; }
public JsonHttpClientFacade(string base_url) : base(base_url) public JsonHttpClientFacade(string base_url, string api_key, bool directConnect = true) : base(base_url, api_key, directConnect)
{ {
ContentType = "application/json"; ContentType = "application/json";
Method = HttpMethod.Post; Method = HttpMethod.Post;
@@ -25,19 +23,16 @@ namespace BS.Shared.Core.Facade
{ {
using (var client = new HttpClient { Timeout = Timeout }) using (var client = new HttpClient { Timeout = Timeout })
{ {
var requestUri = Utilities.WebUtils.CombineUrl(Base_Url, method); var requestUri = BS.Shared.Core.Utilities.WebUtils.CombineUrl(Base_Url, method);
using (var request = new HttpRequestMessage(Method, requestUri)) using (var request = new HttpRequestMessage(Method, requestUri))
{ {
// Add headers await checkForDirect(request).ConfigureAwait(false);
foreach (var header in Headers)
request.Headers.TryAddWithoutValidation(header.Key, header.Value);
// Add body if POST or PUT // Add body if POST or PUT
if (Method == HttpMethod.Post || Method == HttpMethod.Put) if (Method == HttpMethod.Post || Method == HttpMethod.Put)
{ {
var json = JsonConvert.SerializeObject(JsonObject); var json = JsonConvert.SerializeObject(JsonObject);
//File.WriteAllText(@"C:\temp\request.json", json);
request.Content = new StringContent(json, Encoding, "application/json"); request.Content = new StringContent(json, Encoding, "application/json");
} }

View File

@@ -1,7 +1,4 @@
using BS.Shared.Extensions; using BS.Shared.Extensions;
using DevExpress.DataAccess.Native.EntityFramework;
using DevExpress.DataAccess.Native.Web;
using DevExpress.XtraRichEdit.Import.Html;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -12,7 +9,7 @@ using System.Security.Policy;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace BS.Shared.Core.Facade namespace BeWo.Server.ApiFacade.Core
{ {
public class WebClientFacade public class WebClientFacade
{ {

View File

@@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die einer Assembly zugeordnet sind.
[assembly: AssemblyTitle("ClassLibrary1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ClassLibrary1")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("4b2f3959-3cda-4514-83a2-fa3c24e57bb7")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,20 @@
Hallo zusammen! Dies ist eine kleine Info über das Projekt.
Ich habe mir dieses Projekt auf der selben Ebenen wie Data gedacht.
Data: ist ein Projekt, was speziell für die Datenbank Logik dient.
ApiFacade: soll im Gegenzug ein Projekt darstellen, was rein für die API Kommunikation gedacht ist.
Aktuell beinhaltet es die basischen Klassen HttpClientFacade und JsonHttpClientFacade.
WebClientFacade wird nicht benutzt.
HttpClientFacade stellt eine Facade für einen Api Endpunkt bereit, welche mit GET angesporchen werden.
Parameter werden dabei in der Query übergeben, der Body bleibt unberüht!
JsonClientFacade stellt eine Facade für Api Endpunkte bereit, welche mit POST angesprochen werden.
Es wäre hier definitiv eine Überlegung wert, ob man die konkreten Implentiereungen nicht doch auch hier vornimmt,
sauber getrennt durch Ordner.
Das wäre auch nicht so schlecht, weil Data als Idee auch abgeschlossen für die DB Interaktionen dient.
Ich behalte das mal im Hinterkopf, es würde wenn den gesamten Ordner Server/Features/AICore/Facade betreffen.
Danke fürs lesen :)

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BeWo.Service
{
public enum WebConfigSetting
{
OpenWebUIUrl,
XRechnungApiUrl,
StoredFilesFolderPath,
StoredTenantFilesFolderPath,
HelloWorldPdfLocation,
ServiceLogFilePath,
WCFErrorLogFilePath,
JsonErrorLogFilePath,
ApiServiceTestFilePath
}
[DefaultValue(None)]
public enum WebSecretConfigSetting
{
None = -1,
OpenWebUIKey,
GetGkvSumApiKey,
DownloadReportApiKey,
OpenrouteServiceApiKey,
GoogleDistanceMatrixApiKey,
GkvSecretKey,
}
[DefaultValue(None)]
public enum IPAddressList
{
None = -1,
AdminApi
}
[DefaultValue(None)]
public enum SpecialConfig
{
None = -1,
AiConfig
}
}

View File

@@ -23,7 +23,7 @@ namespace BeWo.Service.DCEntityMapper
pDataContract.Max_Gen_Len = pEntity.Max_Gen_Len; pDataContract.Max_Gen_Len = pEntity.Max_Gen_Len;
pDataContract.Context_Type = pEntity.Context_Type; pDataContract.Context_Type = pEntity.Context_Type;
pDataContract.SelectedModel = MapperFactory.AiModel.MapToNewDC(pEntity.SelectedModel); pDataContract.SelectedModel = MapperFactory.AiModel.CreateOrMapToNewDC(pEntity.SelectedModel, true);
return pDataContract; return pDataContract;
} }

View File

@@ -0,0 +1,25 @@
using BS.Shared.Exceptions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BeWo.Service.Extensions
{
public static class ServiceEnumExtension
{
public static string GetConfigPath(this SpecialConfig specialConfig)
{
var root = AppDomain.CurrentDomain.BaseDirectory;
switch (specialConfig)
{
case SpecialConfig.AiConfig: return Path.Combine(root, "Config/ai.config.json");
}
throw BeWoNotImplementedException.CreateFromEnum(specialConfig);
}
}
}

View File

@@ -23,6 +23,7 @@ using BS.Shared.DataContracts.Compact;
using BS.Shared.DataContracts.Feature.AI; using BS.Shared.DataContracts.Feature.AI;
using BS.Shared.Exceptions; using BS.Shared.Exceptions;
using BS.Shared.Extensions; using BS.Shared.Extensions;
using DevExpress.Charts.Native;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace BeWo.Service.Plugins namespace BeWo.Service.Plugins
@@ -237,9 +238,10 @@ namespace BeWo.Service.Plugins
private IEnumerable<AiModel> getAiModels() private IEnumerable<AiModel> getAiModels()
{ {
var old_models = DAOFactory.GenericDAO.GetAll<AiModel>(); var old_models = DAOFactory.GenericDAO.GetAll<AiModel>();
var new_models = ServiceFacade.OpenWebApiClient.GetAiModelle().GetResponseData(); var new_models = ServiceFacade.ActiveAiClient.GetAiModelle().GetResponseData();
var unknown_models = new_models.ToList(); var unknown_models = new_models.ToList();
int i = 0;
foreach (var old_model in old_models) foreach (var old_model in old_models)
{ {
bool found = false; bool found = false;
@@ -251,12 +253,13 @@ namespace BeWo.Service.Plugins
DAOFactory.GenericDAO.SetActivationType(old_model, BS.Shared.ActivationTypeId.Active); DAOFactory.GenericDAO.SetActivationType(old_model, BS.Shared.ActivationTypeId.Active);
found = true; found = true;
unknown_models.Remove(new_model); var index = unknown_models.IndexOf(model => model.Equals(new_model));
unknown_models.RemoveAt(index);
break; break;
} }
} }
if (!found) if (!found && old_model.IsActive == BS.Shared.ActivationTypeId.Active)
DAOFactory.GenericDAO.Deactivate(old_model); DAOFactory.GenericDAO.Deactivate(old_model);
} }
@@ -344,7 +347,7 @@ namespace BeWo.Service.Plugins
// Send Request, wait for Response // Send Request, wait for Response
var dt_before_request = DateTime.Now; var dt_before_request = DateTime.Now;
var response = ServiceFacade.OpenWebApiClient.SendAiMessageRequest(payload, out var message2, out var model, out var duration); var response = ServiceFacade.ActiveAiClient.SendAiMessageRequest(payload, out var message2, out var model, out var duration);
if (!response.Success) if (!response.Success)
{ {

View File

@@ -224,7 +224,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Api\ErrorExtractor\DefaultErrorExtractor.cs" /> <Compile Include="BeWoServiceEnums.cs" />
<Compile Include="Core\DiamantExporter.cs" /> <Compile Include="Core\DiamantExporter.cs" />
<Compile Include="Core\ExcelDownload.cs" /> <Compile Include="Core\ExcelDownload.cs" />
<Compile Include="Core\FileAttachmentUtils.cs" /> <Compile Include="Core\FileAttachmentUtils.cs" />
@@ -410,6 +410,7 @@
<Compile Include="Dokumentverwaltung\PlaceholderManager.cs" /> <Compile Include="Dokumentverwaltung\PlaceholderManager.cs" />
<Compile Include="Dokumentverwaltung\DokumentManager.cs" /> <Compile Include="Dokumentverwaltung\DokumentManager.cs" />
<Compile Include="Dokumentverwaltung\CustomerPlaceholderManager.cs" /> <Compile Include="Dokumentverwaltung\CustomerPlaceholderManager.cs" />
<Compile Include="Extensions\ServiceEnumExtension.cs" />
<Compile Include="Import\AvisImport\AvisImportResult.cs" /> <Compile Include="Import\AvisImport\AvisImportResult.cs" />
<Compile Include="Import\AvisImport\LvrAviseImporter.cs" /> <Compile Include="Import\AvisImport\LvrAviseImporter.cs" />
<Compile Include="Import\AvisImport\AviseImporter.cs" /> <Compile Include="Import\AvisImport\AviseImporter.cs" />
@@ -555,13 +556,12 @@
<Compile Include="ServiceImplementations\UserServiceImp.cs" /> <Compile Include="ServiceImplementations\UserServiceImp.cs" />
<Compile Include="ServiceImplementations\ValueListServiceImp.cs" /> <Compile Include="ServiceImplementations\ValueListServiceImp.cs" />
<Compile Include="Configuration\AppSettings.cs" /> <Compile Include="Configuration\AppSettings.cs" />
<Compile Include="ServiceProxy\OpenWebApiClient.cs" /> <Compile Include="ServiceProxy\ServiceFacade.cs" />
<Compile Include="ServiceUtils\DistanceCalculator\AddressRouteManager.cs" /> <Compile Include="ServiceUtils\DistanceCalculator\AddressRouteManager.cs" />
<Compile Include="ServiceUtils\DistanceCalculator\AddressRouteMatrix.cs" /> <Compile Include="ServiceUtils\DistanceCalculator\AddressRouteMatrix.cs" />
<Compile Include="ServiceUtils\DistanceCalculator\GoogleDistanceMatrixAPI.cs" /> <Compile Include="ServiceUtils\DistanceCalculator\GoogleDistanceMatrixAPI.cs" />
<Compile Include="ServiceUtils\DistanceCalculator\IDistanceAPI.cs" /> <Compile Include="ServiceUtils\DistanceCalculator\IDistanceAPI.cs" />
<Compile Include="ServiceUtils\DistanceCalculator\OpenrouteServiceAPI.cs" /> <Compile Include="ServiceUtils\DistanceCalculator\OpenrouteServiceAPI.cs" />
<Compile Include="ServiceProxy\ServiceFacade.cs" />
<Compile Include="ServiceUtils\ServiceTranslator.cs" /> <Compile Include="ServiceUtils\ServiceTranslator.cs" />
<Compile Include="Core\ServiceHelper.cs" /> <Compile Include="Core\ServiceHelper.cs" />
<Compile Include="Core\ServiceValidator.cs" /> <Compile Include="Core\ServiceValidator.cs" />
@@ -610,6 +610,7 @@
</BootstrapperPackage> </BootstrapperPackage>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Api\ErrorExtractor\" />
<Folder Include="ServiceUtils\API\" /> <Folder Include="ServiceUtils\API\" />
<Folder Include="ServiceUtils\Generell\" /> <Folder Include="ServiceUtils\Generell\" />
<Folder Include="Utils\" /> <Folder Include="Utils\" />

View File

@@ -4,7 +4,6 @@ using BeWo.Data.Entities;
using BeWo.Data.Security; using BeWo.Data.Security;
using BeWo.Service.DCEntityMapper; using BeWo.Service.DCEntityMapper;
using BeWo.Service.ServiceContracts; using BeWo.Service.ServiceContracts;
using BeWo.Service.ServiceProxy;
using BS.Shared; using BS.Shared;
using BS.Shared.DataContracts; using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Feature.AI; using BS.Shared.DataContracts.Feature.AI;

View File

@@ -3,13 +3,19 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using AICore.Facade.LLM;
using BeWo.Service.Core;
namespace BeWo.Service.ServiceProxy namespace BeWo.Service.ServiceProxy
{ {
public static class ServiceFacade public static class ServiceFacade
{ {
private static readonly Lazy<OpenWebApiClient> _OpenWebApiClient = new Lazy<OpenWebApiClient>(() => new OpenWebApiClient()); private static readonly Lazy<OpenWebApiClient> _OpenWebApiClient = new Lazy<OpenWebApiClient>(() => new OpenWebApiClient(MergedConfig.GetSetting("OpenWebUIUrl"), MergedConfig.GetSetting("OpenWebUIKey")));
private static readonly Lazy<OllamaApiClient> _OllamaApiClient = new Lazy<OllamaApiClient>(() => new OllamaApiClient(MergedConfig.GetSetting("OllamaUrl"), MergedConfig.GetSetting("OllamaKey")));
public static OpenWebApiClient OpenWebApiClient => _OpenWebApiClient.Value; public static OpenWebApiClient OpenWebApiClient => _OpenWebApiClient.Value;
public static OllamaApiClient OllamaApiClient => _OllamaApiClient.Value;
public static BaseLLMApiClient ActiveAiClient => OllamaApiClient;
} }
} }

View File

@@ -31,6 +31,8 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.Build.Engine" />
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL" />
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Configuration" /> <Reference Include="System.Configuration" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
@@ -38,13 +40,17 @@
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Core\MergedConfig.cs" /> <Compile Include="Core\MergedConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup>
<ProjectReference Include="..\Shared\Shared.csproj">
<Project>{2f50b83d-a3f0-4ec4-979a-3f9b7e3d8ed4}</Project>
<Name>Shared</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> </Project>

View File

@@ -1378,8 +1378,10 @@ namespace BS.Shared
{ {
json, json,
csv, csv,
tsv tsv,
} csv2,
tsv2,
}
public enum AiContextType public enum AiContextType
{ {

View File

@@ -20,10 +20,7 @@ namespace BS.Shared.DataContracts.Feature.AI
Value = value; Value = value;
} }
[JsonProperty("name")]
public string ModelName { get; set; } public string ModelName { get; set; }
[JsonProperty("ollama.details.parameter_size")]
public int Value { get; set; } public int Value { get; set; }
public int CompareTo(AiModelDC other) public int CompareTo(AiModelDC other)
@@ -42,6 +39,7 @@ namespace BS.Shared.DataContracts.Feature.AI
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
return obj is AiModelDC dc && return obj is AiModelDC dc &&
Oid == dc.Oid &&
ModelName == dc.ModelName && ModelName == dc.ModelName &&
Value == dc.Value; Value == dc.Value;
} }

View File

@@ -92,7 +92,23 @@ namespace BS.Shared.Extensions
return -1; return -1;
} }
public static ObservableCollection<T> ToObservableCollection<T>(this IEnumerable<T> pList) public static int IndexOf<T>(this IEnumerable<T> pList, Predicate<T> pItem)
{
int i = 0;
foreach (T iT in pList)
{
if (pItem(iT))
{
return i;
}
i++;
}
return -1;
}
public static ObservableCollection<T> ToObservableCollection<T>(this IEnumerable<T> pList)
{ {
return new ObservableCollection<T>(pList.ToList()); return new ObservableCollection<T>(pList.ToList());
} }

View File

@@ -143,9 +143,6 @@
<Compile Include="Core\AppSettingReader.cs" /> <Compile Include="Core\AppSettingReader.cs" />
<Compile Include="Core\ComplexWohnheimbuchungsRelationHelper.cs" /> <Compile Include="Core\ComplexWohnheimbuchungsRelationHelper.cs" />
<Compile Include="Core\AbstractIDSpecificDefaultClass.cs" /> <Compile Include="Core\AbstractIDSpecificDefaultClass.cs" />
<Compile Include="Core\Facade\HttpClientFacade.cs" />
<Compile Include="Core\Facade\JsonHttpClientFacade.cs" />
<Compile Include="Core\Facade\WebClientFacade.cs" />
<Compile Include="Core\JsonUtils.cs" /> <Compile Include="Core\JsonUtils.cs" />
<Compile Include="Core\MailUtils.cs" /> <Compile Include="Core\MailUtils.cs" />
<Compile Include="Core\Utilities\WebUtils.cs" /> <Compile Include="Core\Utilities\WebUtils.cs" />