diff --git a/AiCoreUnitTest/AiCoreUnitTest.csproj b/AiCoreUnitTest/AiCoreUnitTest.csproj
index 37b1ec8fa..f2c48c473 100644
--- a/AiCoreUnitTest/AiCoreUnitTest.csproj
+++ b/AiCoreUnitTest/AiCoreUnitTest.csproj
@@ -66,6 +66,10 @@
{69D70CA9-0DF9-419E-BFAF-F4539F129BD9}
AICore
+
+ {094331C3-ECEE-4C89-BBFD-4C9DED89F0EF}
+ Service
+
{2F50B83D-A3F0-4EC4-979A-3F9B7E3D8ED4}
Shared
diff --git a/AiCoreUnitTest/OllamaFacadeTest.cs b/AiCoreUnitTest/OllamaFacadeTest.cs
index 57e2a1058..695a7b0ba 100644
--- a/AiCoreUnitTest/OllamaFacadeTest.cs
+++ b/AiCoreUnitTest/OllamaFacadeTest.cs
@@ -1,7 +1,10 @@
using AICore.Facade.LLM;
+using BeWo.Service.Core;
using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.Logging;
using System;
using System.Net;
+using System.Runtime.InteropServices;
namespace AiCoreUnitTest
{
@@ -48,7 +51,8 @@ namespace AiCoreUnitTest
}
};
- var response = client.SendAiMessageRequest(payload, out string message, out string model, out int? duration);
+ var logger = ServiceLogger.GetRequestLogger();
+ var response = client.SendAiMessageRequest(payload, out string message, out string model, out int? duration, logger);
Assert.IsTrue(response?.Success);
}
diff --git a/BeWo/app.config b/BeWo/app.config
index dc7575256..55003482e 100644
--- a/BeWo/app.config
+++ b/BeWo/app.config
@@ -13,19 +13,19 @@
-
+
-
+
-
+
diff --git a/Server/Components/AICore/Facade/LLM/BaseLLMApiClient.cs b/Server/Components/AICore/Facade/LLM/BaseLLMApiClient.cs
index 4e016d020..846e51932 100644
--- a/Server/Components/AICore/Facade/LLM/BaseLLMApiClient.cs
+++ b/Server/Components/AICore/Facade/LLM/BaseLLMApiClient.cs
@@ -7,12 +7,29 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.Json;
+using BS.Shared.Interface;
+using BeWo.ServerUtils.ApiFacade;
+using BS.Shared.Logger;
namespace AICore.Facade.LLM
{
public abstract class BaseLLMApiClient
{
+ private protected readonly HttpClientFacade _GetClientFacade;
+ private protected readonly JsonHttpClientFacade _PostClientFacade;
+ private protected readonly IApiErrorExtractor _ErrorExtractor;
+
+ protected BaseLLMApiClient(string base_url, string api_key)
+ {
+ _GetClientFacade = new HttpClientFacade(base_url, api_key, false);
+ _PostClientFacade = new JsonHttpClientFacade(base_url, api_key, false)
+ {
+ Timeout = TimeSpan.FromMinutes(10)
+ };
+ _ErrorExtractor = new DefaultErrorExtractor();
+ }
+
public abstract ApiResponse> GetAiModelle();
- public abstract ApiResponse SendAiMessageRequest(dynamic payload, out string message, out string model, out int? duration);
+ public abstract ApiResponse SendAiMessageRequest(dynamic payload, out string message, out string model, out int? duration, FileLogger logger = null);
}
}
diff --git a/Server/Components/AICore/Facade/LLM/OllamaApiClient.cs b/Server/Components/AICore/Facade/LLM/OllamaApiClient.cs
index dc2cc9960..37f9c04d6 100644
--- a/Server/Components/AICore/Facade/LLM/OllamaApiClient.cs
+++ b/Server/Components/AICore/Facade/LLM/OllamaApiClient.cs
@@ -8,23 +8,16 @@ using System.Linq;
using System.Net.Sockets;
using System.Net;
using BeWo.ServerUtils.ApiFacade;
+using BS.Shared;
+using BS.Shared.Logger;
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)
+ public OllamaApiClient(string base_url, string api_key) : base(base_url, api_key)
{
- _GetClientFacade = new HttpClientFacade(base_url, api_key, false);
- _PostClientFacade = new JsonHttpClientFacade(base_url, api_key, false)
- {
- Timeout = TimeSpan.FromMinutes(10)
- };
- _ErrorExtractor = new DefaultErrorExtractor();
+
}
public override ApiResponse> GetAiModelle()
@@ -60,7 +53,7 @@ namespace AICore.Facade.LLM
return ApiResponse>.SuccessResponse(data);
}
- public override ApiResponse SendAiMessageRequest(dynamic payload, out string message, out string model, out int? duration)
+ public override ApiResponse SendAiMessageRequest(dynamic payload, out string message, out string model, out int? duration, FileLogger logger = null)
{
message = null;
duration = null;
@@ -68,6 +61,12 @@ namespace AICore.Facade.LLM
_PostClientFacade.JsonObject = payload;
+ if(logger is object)
+ {
+ logger.Log(LogLevel.Info, "Request:");
+ logger.LogJson(LogLevel.Info, _PostClientFacade.JsonObject);
+ }
+
var response_format = new
{
id = string.Empty,
@@ -89,6 +88,12 @@ namespace AICore.Facade.LLM
var response = _PostClientFacade.GetAnonymousTypeAsync("api/ollama/chat/completions", response_format, _ErrorExtractor).GetAwaiter().GetResult();
+ if(logger is object)
+ {
+ logger.Log(LogLevel.Info, "Response:");
+ logger.LogJson(LogLevel.Info, response);
+ }
+
if (!response.Success)
return response.Copy();
diff --git a/Server/Components/AICore/Facade/LLM/OpenWebApiClient.cs b/Server/Components/AICore/Facade/LLM/OpenWebApiClient.cs
index 9ef7bc061..703a2f5bb 100644
--- a/Server/Components/AICore/Facade/LLM/OpenWebApiClient.cs
+++ b/Server/Components/AICore/Facade/LLM/OpenWebApiClient.cs
@@ -1,8 +1,10 @@
using BeWo.ServerUtils.ApiFacade;
+using BS.Shared;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Feature.AI;
using BS.Shared.Extensions;
using BS.Shared.Interface;
+using BS.Shared.Logger;
using System;
using System.Collections.Generic;
using System.IO;
@@ -13,18 +15,9 @@ namespace AICore.Facade.LLM
{
public class OpenWebApiClient : BaseLLMApiClient
{
- private protected readonly HttpClientFacade _GetClientFacade;
- private protected readonly JsonHttpClientFacade _PostClientFacade;
- private protected readonly IApiErrorExtractor _ErrorExtractor;
-
- public OpenWebApiClient(string base_url, string api_key)
+ public OpenWebApiClient(string base_url, string api_key) : base(base_url, api_key)
{
- _GetClientFacade = new HttpClientFacade(base_url, api_key);
- _PostClientFacade = new JsonHttpClientFacade(base_url, api_key)
- {
- Timeout = TimeSpan.FromMinutes(10)
- };
- _ErrorExtractor = new DefaultErrorExtractor();
+
}
public override ApiResponse> GetAiModelle()
@@ -60,7 +53,7 @@ namespace AICore.Facade.LLM
return ApiResponse>.SuccessResponse(data);
}
- public override ApiResponse SendAiMessageRequest(dynamic payload, out string message, out string model, out int? duration)
+ public override ApiResponse SendAiMessageRequest(dynamic payload, out string message, out string model, out int? duration, FileLogger logger = null)
{
message = null;
duration = null;
@@ -68,6 +61,12 @@ namespace AICore.Facade.LLM
_PostClientFacade.JsonObject = payload;
+ if (logger is object)
+ {
+ logger.Log(LogLevel.Info, "Request:");
+ logger.LogJson(LogLevel.Info, _PostClientFacade.JsonObject);
+ }
+
var response_format = new
{
id = string.Empty,
@@ -93,6 +92,12 @@ namespace AICore.Facade.LLM
var response = _PostClientFacade.GetAnonymousTypeAsync("api/chat/completions", response_format, _ErrorExtractor).GetAwaiter().GetResult();
+ if (logger is object)
+ {
+ logger.Log(LogLevel.Info, "Response:");
+ logger.LogJson(LogLevel.Info, response);
+ }
+
if (!response.Success)
return response.Copy();
diff --git a/Service/Core/PathHelper.cs b/Service/Core/PathHelper.cs
index 4f27bac23..55069a236 100644
--- a/Service/Core/PathHelper.cs
+++ b/Service/Core/PathHelper.cs
@@ -9,14 +9,62 @@ namespace BeWo.Service.Core
{
public static class PathHelper
{
- #region AI
- private static string GetAiPath()
- => Path.Combine(getRoot(), "AI");
- public static string GetAiSystemPromptPath()
- => Path.Combine(GetAiPath(), "systemPrompts");
- #endregion
+ ///
+ /// Holt den Ordner, wo sich die systemInstructions befinden
+ ///
+ public static string GetAiSystemInstructionPath()
+ => Path.Combine(getRoot(), "AI", "systemInstructions");
+
+ public static string GetOrCreateUniqueRequestLogFile()
+ {
+ var folder_path = Path.Combine(getExecutionRoot(), "logs", "ai", "requests");
+ Directory.CreateDirectory(folder_path);
+
+ var file_name = getUniqueFileName(folder_path, $"{DateTime.Now:yyyy.MM.dd HH_mm_ss}", 20);
+
+ if (file_name == null)
+ return null;
+
+ return Path.Combine(folder_path, file_name + ".log");
+ }
+
+ ///
+ /// Holt den Server Root Path
+ /// Normalerweise: C:/BeWoPlaner
+ ///
private static string getRoot()
=> MergedConfig.GetSetting(WebConfigSetting.BeWoPlanerServiceRoot);
+
+ ///
+ /// Holt den Service Root Path
+ /// Normalerweise: C:/BeWoPlaner/service/Host
+ ///
+ private static string getExecutionRoot()
+ => AppDomain.CurrentDomain.BaseDirectory;
+
+
+ private static string getUniqueFileName(string folderPath, string fileName, int retries)
+ {
+ var path = Path.Combine(folderPath, fileName);
+
+ if (!File.Exists(path))
+ return fileName;
+
+ var name = 2;
+ while(retries-- > 0)
+ {
+ var new_fileName = fileName + $" ({name})";
+ var new_path = Path.Combine(folderPath, new_fileName);
+
+ if (!File.Exists(new_path))
+ return new_fileName;
+
+ name++;
+ }
+
+ return null;
+
+ }
}
}
diff --git a/Service/Core/ServiceHelper.cs b/Service/Core/ServiceHelper.cs
index 62288daa1..7bba45b55 100644
--- a/Service/Core/ServiceHelper.cs
+++ b/Service/Core/ServiceHelper.cs
@@ -8,16 +8,13 @@ using System.Threading.Tasks;
using System.ServiceModel.Dispatcher;
using BeWo.Service.ServiceUtils;
using BS.Shared.Extensions;
+using BS.Shared.Logger;
using BeWo.ServerUtils;
namespace BeWo.Service.Core
{
public static class ServiceHelper
{
- public static FileLogger CoreLogger { get; } = new FileLogger(MergedConfig.GetSetting(WebConfigSetting.ServiceLogFilePath));
- public static FileLogger WCFErrorLogger { get; } = new FileLogger(MergedConfig.GetSetting(WebConfigSetting.WCFErrorLogFilePath));
- public static FileLogger JsonErrorLogger { get; } = new FileLogger(MergedConfig.GetSetting(WebConfigSetting.JsonErrorLogFilePath));
-
public static Tuple GetInterfaceAndMethodWCF(Message request, IClientChannel channel)
{
var lTemp = request.Headers.Action.Split("/");
diff --git a/Service/Core/ServiceLogger.cs b/Service/Core/ServiceLogger.cs
new file mode 100644
index 000000000..f1f9a14f7
--- /dev/null
+++ b/Service/Core/ServiceLogger.cs
@@ -0,0 +1,27 @@
+using BS.Shared.Logger;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BeWo.Service.Core
+{
+ public static class ServiceLogger
+ {
+ public static FileLogger CoreLogger { get; } = new FileLogger(MergedConfig.GetSetting(WebConfigSetting.ServiceLogFilePath));
+ public static FileLogger WCFErrorLogger { get; } = new FileLogger(MergedConfig.GetSetting(WebConfigSetting.WCFErrorLogFilePath));
+ public static FileLogger JsonErrorLogger { get; } = new FileLogger(MergedConfig.GetSetting(WebConfigSetting.JsonErrorLogFilePath));
+
+ public static FileLogger GetRequestLogger()
+ {
+ var filePath = PathHelper.GetOrCreateUniqueRequestLogFile();
+
+ if (filePath == null)
+ throw new NotImplementedException("err98462");
+
+ return new FileLogger(filePath);
+ }
+ }
+}
diff --git a/Service/Plugins/AiFunctionService.cs b/Service/Plugins/AiFunctionService.cs
index 9b9e52054..722900736 100644
--- a/Service/Plugins/AiFunctionService.cs
+++ b/Service/Plugins/AiFunctionService.cs
@@ -32,7 +32,7 @@ namespace BeWo.Service.Plugins
// Anfrage zusammensetzen
var context = AiFunctionContextLoader.LoadServiceRecordDocumentationContext(request);
- var systemInstructionsFolderPath = PathHelper.GetAiSystemPromptPath();
+ var systemInstructionsFolderPath = PathHelper.GetAiSystemInstructionPath();
var factory = new AiFunctionSystemInstructionBuilder(systemInstructionsFolderPath);
var system_prompt = factory.CreateServiceRecordDocumentationSystemInstructions(context);
@@ -76,7 +76,8 @@ namespace BeWo.Service.Plugins
}
};
- var response = ServiceFacade.OllamaApiClient.SendAiMessageRequest(payload, out string message, out string model, out int? duration);
+ var logger = ServiceLogger.GetRequestLogger();
+ var response = ServiceFacade.OllamaApiClient.SendAiMessageRequest(payload, out string message, out string model, out int? duration, logger);
return message;
}
diff --git a/Service/Plugins/AiService2.cs b/Service/Plugins/AiService2.cs
index f84299bf9..416cbcff8 100644
--- a/Service/Plugins/AiService2.cs
+++ b/Service/Plugins/AiService2.cs
@@ -270,7 +270,7 @@ namespace BeWo.Service.Plugins
{
var current_user = UserRightHelper.GetLoggedInUserWithOid();
- var systemInstructionsFolderPath = PathHelper.GetAiSystemPromptPath();
+ var systemInstructionsFolderPath = PathHelper.GetAiSystemInstructionPath();
var factory = new AiConversationSystemInstructionBuilder(systemInstructionsFolderPath);
var context_loaded = AiContextLoader.LoadContext(uicontext, context_reference);
@@ -343,13 +343,15 @@ namespace BeWo.Service.Plugins
// Send Request, wait for Response
var dt_before_request = DateTime.Now;
+ var logger = ServiceLogger.GetRequestLogger();
+
ApiResponse response;
string message2, model;
int? duration;
if (config.SelectedModel.ModelSource == AiModelSource.openwebui)
- response = ServiceFacade.OpenWebApiClient.SendAiMessageRequest(payload, out message2, out model, out duration);
+ response = ServiceFacade.OpenWebApiClient.SendAiMessageRequest(payload, out message2, out model, out duration, logger);
else if (config.SelectedModel.ModelSource == AiModelSource.ollama)
- response = ServiceFacade.OllamaApiClient.SendAiMessageRequest(payload, out message2, out model, out duration);
+ response = ServiceFacade.OllamaApiClient.SendAiMessageRequest(payload, out message2, out model, out duration, logger);
else
throw new NotImplementedException();
diff --git a/Service/Plugins/XRechnungService.cs b/Service/Plugins/XRechnungService.cs
index 1a7d9913b..e71637328 100644
--- a/Service/Plugins/XRechnungService.cs
+++ b/Service/Plugins/XRechnungService.cs
@@ -9,6 +9,7 @@ using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.Interface;
+using BS.Shared.Logger;
using DevExpress.Export;
using DevExpress.Utils.Filtering.Internal;
using Newtonsoft.Json;
@@ -35,7 +36,7 @@ namespace BeWo.Service.Plugins
_storage = DAOFactory.GetLocalTenantFileStorage(lStoragePath);
_genericDAO = DAOFactory.GenericDAO;
- _logger = ServiceHelper.CoreLogger;
+ _logger = ServiceLogger.CoreLogger;
}
public ApiResponse> GetXRechnung(long invoice_base_oid, int report_type, string report_url)
diff --git a/Service/Service.csproj b/Service/Service.csproj
index 20e6da829..0b6841bee 100644
--- a/Service/Service.csproj
+++ b/Service/Service.csproj
@@ -228,9 +228,9 @@
-
+
diff --git a/Service/ServiceBehavior/JsonError/JsonErrorHandler.cs b/Service/ServiceBehavior/JsonError/JsonErrorHandler.cs
index 1e4242b14..ed9a09871 100644
--- a/Service/ServiceBehavior/JsonError/JsonErrorHandler.cs
+++ b/Service/ServiceBehavior/JsonError/JsonErrorHandler.cs
@@ -33,7 +33,7 @@ namespace BeWo.Service.ServiceBehavior.JsonError
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
// Logge in File
- ServiceHelper.JsonErrorLogger.LogError(error);
+ ServiceLogger.JsonErrorLogger.LogError(error);
// Erstelle eine JSON-Fehlermeldung
var jsonError = new JsonError
diff --git a/Service/ServiceBehavior/WCFError/WCFErrorHandler.cs b/Service/ServiceBehavior/WCFError/WCFErrorHandler.cs
index ced7ff2e9..d615ce977 100644
--- a/Service/ServiceBehavior/WCFError/WCFErrorHandler.cs
+++ b/Service/ServiceBehavior/WCFError/WCFErrorHandler.cs
@@ -25,7 +25,7 @@ namespace BeWo.Service.ServiceBehavior.WCFError
public void ProvideFault(Exception error, MessageVersion version, ref Message message)
{
// Logge in File
- ServiceHelper.WCFErrorLogger.LogError(error);
+ ServiceLogger.WCFErrorLogger.LogError(error);
var wcfError = Utils.CreateBeWoFaultException(error);
diff --git a/Service/Core/FileLogger.cs b/Shared/Logger/FileLogger.cs
similarity index 96%
rename from Service/Core/FileLogger.cs
rename to Shared/Logger/FileLogger.cs
index 7848727b6..ebd423170 100644
--- a/Service/Core/FileLogger.cs
+++ b/Shared/Logger/FileLogger.cs
@@ -3,7 +3,6 @@ using BS.Shared.Core;
using BS.Shared.Exceptions;
using BS.Shared.Interface;
using Newtonsoft.Json;
-using RestSharp.Validation;
using System;
using System.Collections.Generic;
using System.IO;
@@ -11,7 +10,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace BeWo.Service.Core
+namespace BS.Shared.Logger
{
public class FileLogger
{
diff --git a/Shared/Shared.csproj b/Shared/Shared.csproj
index a0c5b931c..026976987 100644
--- a/Shared/Shared.csproj
+++ b/Shared/Shared.csproj
@@ -429,6 +429,7 @@
+