Merge branch 'master' of ssh://float.ownsoft.de/git/beyondSoft/BeWo

This commit is contained in:
2026-06-25 16:11:24 +02:00
24 changed files with 687 additions and 289 deletions

View File

@@ -1002,6 +1002,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CaritasAichachFriedberg", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PerspektiveAnitaNelles", "ReportImp\PerspektiveAnitaNelles\PerspektiveAnitaNelles.csproj", "{D80E7BBD-F017-4FBB-B3D3-5AD9F43C418D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FabiansDatenbank", "ReportImp\FabiansDatenbank\FabiansDatenbank.csproj", "{2B6F428D-8F97-4638-AF6B-907CB98D9869}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|.NET = Debug|.NET
@@ -12292,6 +12294,30 @@ Global
{D80E7BBD-F017-4FBB-B3D3-5AD9F43C418D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{D80E7BBD-F017-4FBB-B3D3-5AD9F43C418D}.Release|x86.ActiveCfg = Release|Any CPU
{D80E7BBD-F017-4FBB-B3D3-5AD9F43C418D}.Release|x86.Build.0 = Release|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Debug|.NET.ActiveCfg = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Debug|.NET.Build.0 = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Debug|x86.ActiveCfg = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Debug|x86.Build.0 = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.DebugRemote|.NET.ActiveCfg = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.DebugRemote|.NET.Build.0 = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.DebugRemote|Any CPU.ActiveCfg = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.DebugRemote|Any CPU.Build.0 = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.DebugRemote|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.DebugRemote|Mixed Platforms.Build.0 = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.DebugRemote|x86.ActiveCfg = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.DebugRemote|x86.Build.0 = Debug|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Release|.NET.ActiveCfg = Release|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Release|.NET.Build.0 = Release|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Release|Any CPU.Build.0 = Release|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Release|x86.ActiveCfg = Release|Any CPU
{2B6F428D-8F97-4638-AF6B-907CB98D9869}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -12787,6 +12813,7 @@ Global
{A65F19C6-A523-4566-8855-9141B9435B95} = {D8A691C5-146D-4613-86CC-438F02FE9106}
{279D4AEA-239C-4A2C-91DE-735EB7A72F96} = {D8A691C5-146D-4613-86CC-438F02FE9106}
{D80E7BBD-F017-4FBB-B3D3-5AD9F43C418D} = {D8A691C5-146D-4613-86CC-438F02FE9106}
{2B6F428D-8F97-4638-AF6B-907CB98D9869} = {D8A691C5-146D-4613-86CC-438F02FE9106}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FBE985BB-9F0F-4DBB-8F94-ABC37A803FF9}

View File

@@ -186,7 +186,8 @@
<HintPath>..\packages\EntityFramework.6.5.1\lib\net45\EntityFramework.SqlServer.dll</HintPath>
</Reference>
<Reference Include="log4net, Version=3.1.0.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\packages\log4net.3.1.0\lib\net462\log4net.dll</HintPath>
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Lib\log4net.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll</HintPath>
@@ -237,7 +238,7 @@
<Reference Include="System.Numerics.Vectors, Version=4.1.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.6.1\lib\net462\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Lib\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -1,17 +1,18 @@
using System;
using System.Diagnostics;
using System.Web.Mvc;
using System.Web.Security;
using BeWo.Data.Access;
using BeWo.Data.Access;
using BeWo.Data.Entities;
using BeWo.Service.DCEntityMapper;
using BeWo.Service.ServiceContracts;
using BeWo.Service.ServiceContracts.Enhanced;
using BeWoPlanerMobil.Models;
using BeWoPlanerMobil.Service;
using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using ReportingService.ServiceContracts;
using System;
using System.Diagnostics;
using System.Web.Mvc;
using System.Web.Security;
namespace BeWoPlanerMobil.Controllers
{
@@ -26,6 +27,7 @@ namespace BeWoPlanerMobil.Controllers
protected readonly IDownloadService DownloadService = new MobileSessionFacade().DownloadService;
protected readonly IReportService ReportService = new MobileSessionFacade().ReportService;
protected readonly IQueryService QueryService = new MobileSessionFacade().QueryService;
protected readonly IAiEnhancedService AiService = new MobileSessionFacade().AiService;
protected const string LeerzeichenFuerGetMethoden = " ";

View File

@@ -11,6 +11,7 @@ using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Compact;
using BS.Shared.DataContracts.Feature.AI;
using BS.Shared.Extensions;
using BS.Shared.Services;
using DevExpress.Utils.Extensions;
@@ -316,8 +317,192 @@ namespace BeWoPlanerMobil.Controllers
}
}
[HttpGet]
[Authorize]
public ActionResult GetAiPromptbausteinFolder()
{
try
{
var folders = AiService.GetAiPromptbausteinFolder(AiActionType.ServiceRecordDocumentation).ToList();
AddFavoriten(folders);
var projected = ProjectAiFolders(folders);
return new JsonResult
{
Data = projected,
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
MaxJsonLength = int.MaxValue
};
}
catch (Exception ex)
{
Response.StatusCode = 500;
Response.TrySkipIisCustomErrors = true;
return Json(new
{
error = ex.GetType().Name,
message = ex.Message,
inner = ex.InnerException?.Message,
stack = ex.StackTrace
}, JsonRequestBehavior.AllowGet);
}
}
[HttpPost]
[Authorize]
public ActionResult StartPrompt(long promptOid)
{
try
{
var conv = new AiConversationDC
{
Created = DateTime.Now,
Updated = DateTime.Now,
ActionType = AiActionType.ServiceRecordDocumentation
};
AiViewContextDC viewContext = CreateAiViewContext();
conv = AiService.CreateAiConversation(conv, viewContext);
var messages = AiService.ExecuteAiConversationWithPrompt(conv.Oid.Value, viewContext, promptOid);
// Die generierte Dokumentation ist die letzte Assistent-Nachricht.
var resultMessage = (messages ?? new AiConversationMessageDC[0])
.LastOrDefault(m => m.Role == AiConversationMessageRole.Assistent)
?? (messages ?? new AiConversationMessageDC[0]).LastOrDefault();
return Json(new
{
success = true,
text = resultMessage?.Message ?? string.Empty
});
}
catch (Exception ex)
{
Log.Error("StartPrompt fehlgeschlagen", ex);
Response.StatusCode = 500;
Response.TrySkipIisCustomErrors = true;
return Json(new
{
success = false,
error = ex.GetType().Name,
message = ex.Message,
inner = ex.InnerException?.Message
});
}
}
/// <summary>
/// Baut den AI-Kontext für die aktuell bearbeitete Einzelbuchung auf:
/// Primary = ausgewähltes Betreuungskonzept, Secondary = aktueller Dokumentationstext.
/// </summary>
private AiViewContextDC CreateAiViewContext()
{
long customerOid = -1;
long scOid = -1;
long cbOid = -1;
var oids = new List<long>();
foreach (var record in Model.ServiceRecords)
{
oids.Add(record.ServiceRecordOid ?? -1);
}
if (Model.SelectedCostBearerSupportConceptOid.HasValue)
{
var c2s = DAOFactory.GenericDAO.LoadByID<CostBearer2SupportConcept>(Model.SelectedCostBearerSupportConceptOid.Value);
customerOid = c2s.SupportConcept.Customer.Oid.Value;
scOid = c2s.SupportConcept.Oid.Value;
cbOid = c2s.CostBearer.Oid.Value;
}
var rtn = new Dictionary<TableID, long[]>()
{
{TableID.Customer, new long[]{ customerOid } },
{TableID.SupportConcept, new long[]{ scOid } },
{TableID.CostBearer, new long[]{ cbOid } },
{TableID.ServiceRecord, oids.ToArray() }
};
var dc = new AiViewContextDC()
{
Primary = scOid,
References = rtn
};
return dc;
}
private void AddFavoriten(List<AiPromptbausteinFolderDC> folders)
{
var favoriten = new AiPromptbausteinFolderDC()
{
Oid = -5,
Title = "Favoriten",
Description = "Eigene Favoriten",
SubPrompts = new List<AiPromptbausteinPromptDC>()
};
AddFavoritenPrompts(folders, favoriten);
folders.Insert(0, favoriten);
}
private void AddFavoritenPrompts(List<AiPromptbausteinFolderDC> folders, AiPromptbausteinFolderDC favoriten)
{
foreach (var folder in folders)
{
if (folder.SubFolders?.Any() ?? false)
AddFavoritenPrompts(folder.SubFolders, favoriten);
foreach (var prompt in folder.SubPrompts)
{
if (prompt.IsFavorite)
favoriten.SubPrompts.Add(prompt);
}
//foreach (var routine in folder.SubRoutines.VMList)
//{
// if (routine.IsFavorite)
// favoriten.SubRoutines.VMList.Add(routine);
//}
}
}
/// <summary>
/// Projiziert die AiPromptbausteinFolderDC-Baumstruktur auf ein schlankes,
/// zirkelbezugsfreies Objekt für die JSON-Serialisierung an das UI.
/// </summary>
private List<object> ProjectAiFolders(List<AiPromptbausteinFolderDC> folders)
{
if (folders == null)
{
return new List<object>();
}
return folders.Select(f => (object)new
{
f.Title,
f.Description,
SubFolders = ProjectAiFolders(f.SubFolders),
SubPrompts = (f.SubPrompts ?? new List<AiPromptbausteinPromptDC>())
.Select(p => new
{
p.Oid,
p.Title,
p.Description,
p.Prompt
}).ToList()
}).ToList();
}
private void InitSettings()
{
//Mandator Settings
Model.ShowBetrag = UserSettingsUtils.GetSettingValueAsBool(Model.Mandator.Settings, SettingsKeys.ShowBetrag);
Model.ShowMarker = UserSettingsUtils.GetSettingValueAsBool(Model.Mandator.Settings, SettingsKeys.ShowMarker);

View File

@@ -60,6 +60,8 @@ namespace BeWoPlanerMobil.Models
public bool HasRightToInsertRessourceAppointments => CheckRight(UserRightType.KalenderRessourcentermineAnlegen) || CheckRight(UserRightType.CreateAll);
public bool HasRightToSeeAiPromptsInZeiterfassung => CheckRight(UserRightType.AiModulePromptbausteineView) && CheckRight(UserRightType.AiModuleServiceRecordDocu);
public bool HasRightToUseAiVoice
{
get

View File

@@ -1,9 +1,11 @@
using System.Web;
using BeWo.Service.ServiceContracts;
using BeWo.Service.ServiceContracts;
using BeWo.Service.ServiceContracts.Enhanced;
using BeWo.Service.ServiceImplementations;
using BeWo.Service.ServiceImplementations.Enhanced;
using BeWoPlanerMobil.Models;
using ReportingService.ServiceContracts;
using ReportingService.ServiceImplementations;
using System.Web;
namespace BeWoPlanerMobil.Service
{
@@ -21,6 +23,7 @@ namespace BeWoPlanerMobil.Service
DownloadService = new DownloadServiceImp();
ReportService = new ReportServiceImp();
QueryService = new QueryServiceImp();
AiService = new AiEnhancedServiceImp();
}
public ICustomerService CustomerService { get; }
@@ -33,6 +36,7 @@ namespace BeWoPlanerMobil.Service
public IDownloadService DownloadService { get; }
public IReportService ReportService { get; }
public IQueryService QueryService { get; }
public IAiEnhancedService AiService { get; }
public static long? LoggedInUserOid
{

View File

@@ -433,7 +433,7 @@
@{
var sbEmployeeInputValue = string.Empty;
if(Model.SelectedEmployee?.EmployeeOid is not null)
if (Model.SelectedEmployee?.EmployeeOid is not null)
{
sbEmployeeInputValue = $"value=\"{Model.SelectedEmployee.EmployeeOid}\"";
}
@@ -445,7 +445,7 @@
</div>
@* ----- Einzelbuchung: Ziele ----- *@
@if(Model.SelectedSupportConcept != null && Model.SelectedSupportConcept.Goals.Any())
@if (Model.SelectedSupportConcept != null && Model.SelectedSupportConcept.Goals.Any())
{
<div class="form-row">
<div class="col-md mt-2">
@@ -490,7 +490,7 @@
</div>
@* ----- Marker ----- *@
@if(Model.ShowMarker)
@if (Model.ShowMarker)
{
var markerCheckedValue = Model.SelectedServiceRecord?.ServiceRecordType == ServiceRecordTypeId.Content ? "checked" : string.Empty;
@@ -505,10 +505,10 @@
}
@* ----- Betrag ----- *@
@if(Model.ShowBetrag)
@if (Model.ShowBetrag)
{
var betrag = string.Empty;
if(Model.SelectedServiceRecord?.Betrag is > 0)
if (Model.SelectedServiceRecord?.Betrag is > 0)
{
betrag = Model.SelectedServiceRecord.Betrag.Value.ToString("#.00");
}
@@ -541,10 +541,10 @@
var afterValidationState = TempData[TempDataConstants.AfterValidationStateKey];
if(Model.SetStartTimeToEndTimeAfterSave && !Model.IsInEditingMode && afterValidationState is false)
if (Model.SetStartTimeToEndTimeAfterSave && !Model.IsInEditingMode && afterValidationState is false)
{
durationValue = Model.NewDuration?.ToString();
if(Model.NewDuration.HasValue)
if (Model.NewDuration.HasValue)
{
durationValue = (Model.NewDuration / divisor).ToString();
}
@@ -564,7 +564,7 @@
<input class="form-control" type="date" name="Datum" id="sb-start-date-input" onchange="calcDuration('sb', false, true, false); window.updateStartDate('sb', $(this).val());" value="@Model.StartDateToEditJSFormat" />
</div>
</div>
@if(Model.IsEndDateVisible)
@if (Model.IsEndDateVisible)
{
<div class="col-md-6 mt-2">
<div class="input-group">
@@ -592,11 +592,11 @@
Von
</span>
</div>
<input class="form-control" type="time" name="Start" id="sb-start-time-input" onchange="calcDuration('sb', false, true, false);window.updateStartTime('sb', $(this).val());" value="@von"/>
<input class="form-control" type="time" name="Start" id="sb-start-time-input" onchange="calcDuration('sb', false, true, false);window.updateStartTime('sb', $(this).val());" value="@von" />
<span class="input-group-text rounded-0 border-left-0 border-right-0">
Bis
</span>
<input class="form-control" type="time" name="Ende" id="sb-end-time-input" onchange="calcDuration('sb', false, false, true);window.updateEndTime('sb', $(this).val());" value="@bis"/>
<input class="form-control" type="time" name="Ende" id="sb-end-time-input" onchange="calcDuration('sb', false, false, true);window.updateEndTime('sb', $(this).val());" value="@bis" />
</div>
</div>
</div>
@@ -615,7 +615,7 @@
</div>
</div>
<input type="text" class="form-control" id="sb-duration-input" name="Dauer" onchange="beiDaueraenderung('sb'); window.updateDuration('sb', $(this).val());" value="@durationValue">
@if(Model.IsZeiterfassungInStdMin)
@if (Model.IsZeiterfassungInStdMin)
{
<div class="input-group-append">
<button id="sb-hours-minutes-dropdown-btn" class="btn btn-outline-primary dropdown-toggle w-100" type="button" data-toggle="dropdown">
@@ -633,7 +633,7 @@
</div>
@* ----- Einzelbuchung: Distanz ----- *@
@if(Model.ShowDistanceField)
@if (Model.ShowDistanceField)
{
<div class="form-row mt-2">
<div class="col-md">
@@ -652,7 +652,7 @@
}
@* ----- Einzelbuchung: Textbausteine ----- *@
@if(Model.HasRightToSeeTextModules)
@if (Model.HasRightToSeeTextModules)
{
<script type="text/javascript">
function textModuleButtonOnClick() {
@@ -665,11 +665,184 @@
</div>
</div>
}
@* ----- Einzelbuchung: KI Funktionen ----- *@
@if (Model.HasRightToSeeAiPromptsInZeiterfassung)
{
<script type="text/javascript">
</script>
<div class="form-row mt-2" id="aifunction-container">
<div class="col-md">
@if (Model.HasRightToUseAiVoice)
{
<button type="button" class="btn btn-primary float-right mr-1" id="aivoice-button" onclick="startExternalCall();" title="KI-Spracheingabe & Transkription" style="padding: 0 0.6em; overflow: hidden; line-height: 0;"><img src="@Url.Content("~/Content/images/Icon_Mikro_Weiss.png")" alt="KI-Spracheingabe & Transkription" style="height:2.25em; display: block;" /></button>
}
<button type="button" class="btn btn-primary float-right mr-1" id="aiprompt-btn" style="padding: 0 0.6em; overflow: hidden; line-height: 0;"><img src="@Url.Content("~/Content/images/Icon_KI_Funktion_Weiss+Gruen.png")" alt="KI-Promptbausteine auswählen" style="height:2.25em; display: block;" /></button>
</div>
</div>
<!-- KI-Promptbausteine Modal -->
<div class="modal fade" id="aiprompt-modal" tabindex="-1" role="dialog" aria-labelledby="aiprompt-modal-title" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="aiprompt-modal-title">KI-Promptbausteine auswählen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Schließen">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="row" style="min-height: 350px;">
<div class="col-md-5 border-right" id="aiprompt-tree-col">
<div id="aiprompt-tree" style="overflow-y: auto; max-height: 400px;">
<div class="text-muted small p-2">Wird geladen…</div>
</div>
</div>
<div class="col-md-7" id="aiprompt-prompts-col">
<div id="aiprompt-prompts-list">
<div class="text-muted small p-2">Bitte einen Ordner auswählen.</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
(function () {
function buildTree(folders, container, level) {
folders.forEach(function (folder) {
var indent = level * 16;
var item = $('<div class="aiprompt-folder-item" style="cursor:pointer; padding: 4px 6px; border-radius:4px; margin-bottom:2px;">'
+ '<span style="display:inline-block; width:' + indent + 'px;"></span>'
+ '<span class="aiprompt-folder-toggle mr-1" style="display:inline-block; width:14px;">'
+ (folder.SubFolders && folder.SubFolders.length > 0 ? '&#9654;' : '&nbsp;')
+ '</span>'
+ '<span class="aiprompt-folder-label"><strong>' + $('<div>').text(folder.Title).html() + '</strong></span>'
+ '</div>');
var subContainer = null;
if (folder.SubFolders && folder.SubFolders.length > 0) {
subContainer = $('<div class="aiprompt-subfolders" style="display:none;"></div>');
buildTree(folder.SubFolders, subContainer, level + 1);
}
item.on('click', function (e) {
e.stopPropagation();
$('.aiprompt-folder-item').removeClass('bg-primary text-white').css('color', '');
item.addClass('bg-primary text-white');
if (subContainer) {
var expanded = subContainer.is(':visible');
subContainer.toggle(!expanded);
item.find('.aiprompt-folder-toggle').html(expanded ? '&#9654;' : '&#9660;');
}
showPrompts(folder.SubPrompts || []);
});
container.append(item);
if (subContainer) container.append(subContainer);
});
}
function showPrompts(prompts) {
var list = $('#aiprompt-prompts-list').empty();
if (!prompts || prompts.length === 0) {
list.html('<div class="text-muted small p-2">Keine Prompts in diesem Ordner.</div>');
return;
}
prompts.forEach(function (p) {
var card = $('<div class="card mb-2" style="cursor:pointer;"></div>');
var body = $('<div class="card-body p-2"></div>');
body.append($('<h6 class="card-title mb-1"></h6>').text(p.Title));
if (p.Description) body.append($('<p class="card-text small text-muted mb-0"></p>').text(p.Description));
card.append(body);
card.on('click', function () {
if (p.Oid == null) return;
// Prompt server-seitig ausführen und Ergebnis ins Doku-Feld schreiben
var $card = $(this);
$('#aiprompt-prompts-list .card').css('pointer-events', 'none').css('opacity', '0.5');
$card.css('opacity', '1').append(
'<div class="aiprompt-loading text-muted small mt-1">'
+ '<span class="spinner-border spinner-border-sm mr-1"></span>Wird ausgeführt …</div>');
$.ajax({
url: '@Url.Action("StartPrompt", "Main")',
type: 'POST',
data: { promptOid: p.Oid },
success: function (resp) {
$('#aiprompt-modal').modal('hide');
var text = resp && resp.text ? resp.text : '';
var activeTextarea = $('textarea:visible:first[id^="sb-doku-textarea"]');
if (activeTextarea.length && text) {
var current = activeTextarea.val();
activeTextarea.val(current ? current + '\n' + text : text).trigger('change');
}
},
error: function (xhr) {
var msg = 'Fehler beim Ausführen des Prompts.';
try {
var r = JSON.parse(xhr.responseText);
if (r && r.message) msg += '\n' + r.message;
} catch (e) { }
console.error('StartPrompt Fehler:', xhr.status, xhr.responseText);
$('.aiprompt-loading').remove();
$('#aiprompt-prompts-list .card').css('pointer-events', '').css('opacity', '');
alert(msg);
}
});
});
list.append(card);
});
}
var dataLoaded = false;
$('#aiprompt-btn').on('click', function () {
$('#aiprompt-modal').modal('show');
if (dataLoaded) return;
$.ajax({
url: '@Url.Action("GetAiPromptbausteinFolder", "Main")',
type: 'GET',
success: function (data) {
dataLoaded = true;
var tree = $('#aiprompt-tree').empty();
if (!data || data.length === 0) {
tree.html('<div class="text-muted small p-2">Keine Ordner verfügbar.</div>');
return;
}
buildTree(data, tree, 0);
},
error: function (xhr, textStatus, errorThrown) {
var details = 'Status: ' + xhr.status + ' ' + (xhr.statusText || '')
+ '\ntextStatus: ' + textStatus
+ '\nerror: ' + errorThrown;
if (xhr.responseText) {
details += '\n\nAntwort:\n' + xhr.responseText.substring(0, 4000);
}
console.error('GetAiPromptbausteinFolder Fehler:', details);
$('#aiprompt-tree').html(
'<div class="text-danger small p-2">Fehler beim Laden der Promptbausteine.<br/>'
+ '<pre style="white-space:pre-wrap; font-size:11px; max-height:320px; overflow:auto;">'
+ $('<div>').text(details).html()
+ '</pre></div>');
}
});
});
})();
</script>
}
@* ----- Einzelbuchung: Dokumentation ----- *@
<div class="form-row">
<div class="col-md mt-3">
@if(Model.NumberOfDokuTypes == 0)
@if (Model.NumberOfDokuTypes == 0)
{
<div class="form-group my-0">
<label for="sb-doku-textarea-5">Dokumentation</label>
@@ -679,7 +852,7 @@
else
{
<ul class="nav nav-tabs" role="tab-list">
@for(var i = 0; i < Model.Dokutypes.Length; i++)
@for (var i = 0; i < Model.Dokutypes.Length; i++)
{
var currentDokuType = Model.Dokutypes[i];
@@ -691,7 +864,7 @@
}
</ul>
<div class="tab-content" id="dokufelderTab">
@for(var i = 0; i < Model.Dokutypes.Length; i++)
@for (var i = 0; i < Model.Dokutypes.Length; i++)
{
var textareaName = i + 1 < 1 ? "Dokumentation" : "Dokumentation" + (i + 1);
@@ -728,11 +901,6 @@
<button type="button" class="btn btn-primary float-right" id="reset-button" onclick="resetSingleBookingForm();">Abbrechen</button>
}
@if (Model.HasRightToUseAiVoice)
{
<button type="button" class="btn btn-primary float-right mr-1" id="aivoice-button" onclick="startExternalCall();" title="KI-Spracheingabe & Transkription" style="padding: 0 0.6em; overflow: hidden; line-height: 0;"><img src="@Url.Content("~/Content/images/Icon_Mikro_Weiss.png")" alt="KI-Spracheingabe & Transkription" style="height:2.25em; display: block;" /></button>
}
@Html.Partial("RestoreServiceRecordInputsPartial", Model)

View File

@@ -170,6 +170,8 @@
<add key="PluginBasePath" value="..\CustomerDlls" />
<add key="PluginPath" value="..\CustomerDlls" />
<add key="FileRootDirectory" value="\BWP-Files" />
<add key="AiPromptsUrl" value="https://test2.evplaner.de" />
</appSettings>
<!--
Eine Beschreibung der Änderungen von 'web.config' finden Sie unter 'http://go.microsoft.com/fwlink/?LinkId=235367'.
@@ -306,7 +308,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-6.0.3.0" newVersion="6.0.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />

Binary file not shown.

View File

@@ -12,6 +12,7 @@ using System.ComponentModel.Design;
using System.Runtime.Remoting.Messaging;
using log4net;
using BS.Shared.Core;
using BeWo.ServerUtils.Core;
namespace AICore.Facade
{

View File

@@ -13,6 +13,7 @@ using BS.Shared.Logger;
using log4net;
using System.Runtime.CompilerServices;
using BS.Shared.Core;
using BeWo.ServerUtils.Core;
namespace AICore.Facade.LLM
{

View File

@@ -1,4 +1,5 @@
using BS.Shared.Core;
using BeWo.ServerUtils.Core;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.Exceptions;
using BS.Shared.Interface;

View File

@@ -0,0 +1,30 @@
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BeWo.ServerUtils.Core
{
public static class LoggerUtils
{
private static bool _LoggerInit = false;
public static void InitLogger()
{
if (_LoggerInit) return;
log4net.Config.XmlConfigurator.Configure();
_LoggerInit = true;
}
public static ILog GetLogger(Type declaringType)
{
InitLogger();
return log4net.LogManager.GetLogger(declaringType);
}
}
}

View File

@@ -89,6 +89,7 @@
<ItemGroup>
<Compile Include="ApiFacade\HttpClientFacade.cs" />
<Compile Include="ApiFacade\JsonHttpClientFacade.cs" />
<Compile Include="Core\LoggerUtils.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
@@ -98,9 +99,7 @@
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Folder Include="Core\" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<ProjectReference Include="..\..\..\Shared\Shared.csproj">
<Project>{2f50b83d-a3f0-4ec4-979a-3f9b7e3d8ed4}</Project>

View File

@@ -1,4 +1,5 @@
using BS.Shared.Core;
using BeWo.ServerUtils.Core;
using BS.Shared.Core;
using System;
using System.ServiceModel.Configuration;

View File

@@ -389,7 +389,13 @@ namespace BeWo.Service.Plugins
var actionType = conversation.ActionType;
var context_Type = config.Context_Type;
var context_loaded = AiContextLoader.LoadContext(actionType, view_context, prompt?.SamplesCount);
var sampleCount = prompt?.SamplesCount;
if(prompt is object && !prompt.IsOwnsoftPrompt)
{
sampleCount = null;
}
var context_loaded = AiContextLoader.LoadContext(actionType, view_context, sampleCount);
var configPath = getPromptPath(actionType);
var system_prompt = AiSystemPromptFactory.BuildContext(actionType, configPath, context_loaded, context_Type);

View File

@@ -1,4 +1,5 @@
using BeWo.Data.Access;
using BeWo.ServerUtils.Core;
using BeWo.Service.Core;
using BS.Shared.Core;
using System;

View File

@@ -1,4 +1,5 @@
using BeWo.Service.Core;
using BeWo.ServerUtils.Core;
using BeWo.Service.Core;
using BS.Shared.Core;
using DevExpress.CodeParser.Diagnostics;
using log4net;

View File

@@ -9118,7 +9118,7 @@ namespace BeWo.Service.ServiceImplementations
try
{
var list = new List<InactivePersonDC>();
//return list;
return list;
var sql = @"select null, p.Oid as personoid, p.FirstName, p.LastName, p.DateOfBirth, a.Street as Strasse, a.PostalCode as PLZ, a.Town as Ort, p.insts from person p
left join address a on p.Addressoid = a.Oid
where (p.isactive = 0 or p.isactive = 2) and (p.SystemEntryID is null || p.SystemEntryID != -1)

View File

@@ -1,30 +0,0 @@
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BS.Shared.Core
{
public static class LoggerUtils
{
private static bool _LoggerInit = false;
public static void InitLogger()
{
if(_LoggerInit) return;
log4net.Config.XmlConfigurator.Configure();
_LoggerInit = true;
}
public static ILog GetLogger(Type declaringType)
{
InitLogger();
return log4net.LogManager.GetLogger(declaringType);
}
}
}

View File

@@ -103,9 +103,6 @@
<Reference Include="DevExpress.XtraReports.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.XtraScheduler.v23.2.Core.Desktop, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.XtraScheduler.v23.2.Core, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="log4net">
<HintPath>..\Lib\log4net.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
@@ -152,7 +149,6 @@
<Compile Include="Core\Facade\HttpClientFacade.cs" />
<Compile Include="Core\Facade\JsonHttpClientFacade.cs" />
<Compile Include="Core\JsonUtils.cs" />
<Compile Include="Core\LoggerUtils.cs" />
<Compile Include="Core\MailUtils.cs" />
<Compile Include="Core\Rule\GkvRules.cs" />
<Compile Include="Core\SecurityUtils.cs" />