From fe7f2da2c9b0ec631f5209b04e65bd15b1ed4b33 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 30 Mar 2026 00:07:52 +0200 Subject: [PATCH] =?UTF-8?q?AI=20Voice=20zum=20Mok=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/CustomerController.cs | 2 +- BeWoPlanerMobil/Controllers/MainController.cs | 134 +++++++++++++++++ BeWoPlanerMobil/Models/AbstractModel.cs | 53 ++++++- BeWoPlanerMobil/Models/MokMandator.cs | 1 + .../ownSoft-Scripts/view-scripts/main.js | 2 + .../Views/Main/SingleBookingPartial.cshtml | 142 +++++++++++++++--- BeWoPlanerMobil/Views/Shared/_Layout.cshtml | 2 +- 7 files changed, 314 insertions(+), 22 deletions(-) diff --git a/BeWoPlanerMobil/Controllers/CustomerController.cs b/BeWoPlanerMobil/Controllers/CustomerController.cs index 8066b5d75..19d89099b 100644 --- a/BeWoPlanerMobil/Controllers/CustomerController.cs +++ b/BeWoPlanerMobil/Controllers/CustomerController.cs @@ -146,7 +146,7 @@ namespace BeWoPlanerMobil.Controllers return; } - if(customerOid == -1) + if(customerOid <= 0) { Model.CustomerSessionModel.ResetValues(); } diff --git a/BeWoPlanerMobil/Controllers/MainController.cs b/BeWoPlanerMobil/Controllers/MainController.cs index db61af0c6..aaf240883 100644 --- a/BeWoPlanerMobil/Controllers/MainController.cs +++ b/BeWoPlanerMobil/Controllers/MainController.cs @@ -16,6 +16,7 @@ using DevExpress.XtraScheduler; using DevExpress.XtraScheduler.Compatibility; using Newtonsoft.Json; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; @@ -31,6 +32,7 @@ using FormCollection = System.Web.Mvc.FormCollection; using GoalRating = BeWoPlanerMobil.Util.GoalRating; using Image = System.Drawing.Image; using ServiceRecordDC = BS.Shared.DataContracts.ServiceRecordDC; +using BeWo.Service.AI; /* * ToDo: Bug, wenn man auf "bearbeiten" bei einem Eintrag klickt, wird die Leistung nicht geladen @@ -41,6 +43,13 @@ namespace BeWoPlanerMobil.Controllers { public class MainController : SignableController { + // Speichert den Status externer Aufrufe (callId -> Callback-Daten) + private static readonly ConcurrentDictionary _externalCallResults = new ConcurrentDictionary(); + // Speichert optionale Statusmeldungen für laufende externe Aufrufe (callId -> Statustext) + private static readonly ConcurrentDictionary _externalCallStatusMessages = new ConcurrentDictionary(); + // Speichert das Aufnametoken für laufende externe Aufrufe (callId -> Token) + private static readonly ConcurrentDictionary _externalCallTokens = new ConcurrentDictionary(); + public MainController() { int test = 0; @@ -3557,6 +3566,131 @@ namespace BeWoPlanerMobil.Controllers return View("Main", Model); } + /// + /// Ermittelt die externe URL, die beim Klick auf den Test-Button aufgerufen werden soll. + /// Die callbackUrl wird als Parameter mitgegeben, damit das externe System sie verwenden kann. + /// + [HttpGet] + [Authorize] + public JsonResult GetExternalCallUrl(string callId, string callbackUrl) + { + try + { + var externalUrl = ""; + + if (Mandator?.OwnChatCode != null) + { + var ts = new TranscriptionService(); + var avd = ts.InitTranskription(MobileSessionFacade.Tenant, false); + + externalUrl = avd.ResultUrl; + + if (!string.IsNullOrEmpty(callId) && !string.IsNullOrEmpty(avd.Token)) + { + _externalCallTokens[callId] = ts.MapAiVoiceDataDC(avd); + } + + //var externalBaseUrl = "https://example.com/external-service"; + //var externalUrl = externalBaseUrl + // + "?callbackUrl=" + Uri.EscapeDataString(callbackUrl) + // + "&callId=" + Uri.EscapeDataString(callId); + } + + + return Json(new { success = true, url = externalUrl }, JsonRequestBehavior.AllowGet); + } + catch(Exception ex) + { + return Json(new { success = false, message = "Fehler beim Ermitteln der externen URL: " + ex.Message }, JsonRequestBehavior.AllowGet); + } + } + + /// + /// Callback-Endpunkt, der vom externen System aufgerufen wird. + /// Markiert den externen Aufruf als abgeschlossen. + /// + [HttpGet] + [AllowAnonymous] + public ActionResult ExternalCallCallback(string callId, string data = null) + { + if(!string.IsNullOrEmpty(callId)) + { + _externalCallResults[callId] = data ?? string.Empty; + _externalCallStatusMessages.TryRemove(callId, out _); + _externalCallTokens.TryRemove(callId, out _); + } + + return Content("OK"); + } + + /// + /// Kann vom externen System aufgerufen werden, um eine Statusmeldung zu setzen, + /// die dem Benutzer im Wartedialog angezeigt wird (ohne den Vorgang abzuschließen). + /// + [HttpGet] + [AllowAnonymous] + public ActionResult ExternalCallUpdateStatus(string callId, string message) + { + if(!string.IsNullOrEmpty(callId) && message != null) + { + _externalCallStatusMessages[callId] = message; + } + + return Content("OK"); + } + + /// + /// Wird vom Browser per Polling aufgerufen, um zu prüfen ob der Callback bereits eingegangen ist. + /// Gibt bei completed=false optional eine Statusmeldung zurück. + /// + [HttpGet] + [Authorize] + public JsonResult CheckExternalCallStatus(string callId) + { + if(!string.IsNullOrEmpty(callId) && _externalCallResults.TryRemove(callId, out var data)) + { + _externalCallStatusMessages.TryRemove(callId, out _); + _externalCallTokens.TryRemove(callId, out _); + return Json(new { completed = true, data }, JsonRequestBehavior.AllowGet); + } + + string statusMessage = null; + if(!string.IsNullOrEmpty(callId) && _externalCallTokens.TryRemove(callId, out var avddc)) + { + var ts = new TranscriptionService(); + + var avd = ts.MapAiVoiceData(avddc); + + avd = ts.GetTranskription(avd); + statusMessage = avd.StatusMessage; + avddc = ts.MapAiVoiceDataDC(avd); + + _externalCallTokens[callId] = avddc; + + //_externalCallStatusMessages.TryGetValue(callId, out statusMessage); + } + + return Json(new { completed = false, statusMessage }, JsonRequestBehavior.AllowGet); + } + + /// + /// Wird aufgerufen, wenn der Benutzer den externen Aufruf abbricht. + /// Räumt den Eintrag auf, falls vorhanden. + /// + [HttpPost] + [Authorize] + public ActionResult CancelExternalCall(string callId) + { + if(!string.IsNullOrEmpty(callId)) + { + _externalCallResults.TryRemove(callId, out _); + _externalCallStatusMessages.TryRemove(callId, out _); + _externalCallTokens.TryRemove(callId, out _); + } + + return new HttpStatusCodeResult(200); + } + [HttpPost] [Authorize] public ActionResult ResetGroupBookingForm() diff --git a/BeWoPlanerMobil/Models/AbstractModel.cs b/BeWoPlanerMobil/Models/AbstractModel.cs index bceaec876..da1353a2f 100644 --- a/BeWoPlanerMobil/Models/AbstractModel.cs +++ b/BeWoPlanerMobil/Models/AbstractModel.cs @@ -58,11 +58,61 @@ namespace BeWoPlanerMobil.Models public bool HasRightToInsertRessourceAppointments => CheckRight(UserRightType.KalenderRessourcentermineAnlegen) || CheckRight(UserRightType.CreateAll); - public bool HasRightToViewQuittierungsbelege + public bool HasRightToUseAiVoice { get { + var showAiVoice = MobileUtils.GetSettingValue(Mandator.Settings, SettingsKeys.ShowAIVoice); + var showOwnChat = MobileUtils.GetSettingValue(Mandator.Settings, SettingsKeys.ShowChat); + +#if DEBUG + showAiVoice = "1"; + showOwnChat = "1"; + + //tenant = "4368658435"; + //var serverUrl = OwnChatHelper.ErmittleServerURL("1", tenant); + //var apikey = "hNykpBwxE1Y6NmwZBTDQOpPXW6xCgnVHjJ5lh0QDQyCefgcnimC32aZ3CwB4qQl4"; + //var userid = "1432790061"; + + Mandator.OwnChatCode = "HcYki-8hLbQ"; + + return true; +#endif + if ("1".Equals(showAiVoice) && CheckRight(UserRightType.AiVoiceView)) + { + if (LoggedInEmployee != null && Mandator.OwnChatCode == null) + { + Mandator.OwnChatCode = ""; + + if ("1".Equals(showOwnChat)) + { + var es = new BeWo.Service.ServiceImplementations.EmployeeServiceImp(); + var empAppCodes = es.GetAllEmployeeAppCodes(LoggedInEmployee.EmployeeOid.Value); + + if (empAppCodes != null && empAppCodes.Count > 0) + { + foreach (var item in empAppCodes) + { + if (item.EmployeeCode != null && !item.EmployeeCode.Equals("")) + Mandator.OwnChatCode = item.EmployeeCode; + } + } + } + } + } + + + + return !String.IsNullOrEmpty(Mandator.OwnChatCode); + } + } + + public bool HasRightToViewQuittierungsbelege + { + get + { + var showEmployeeSignatureSetting = MobileUtils.GetSettingValue(Mandator.Settings, SettingsKeys.ShowSignature); #if DEBUG showEmployeeSignatureSetting = "1"; @@ -72,7 +122,6 @@ namespace BeWoPlanerMobil.Models } - public bool IsAllowedToSeeSupportConceptFilter { get diff --git a/BeWoPlanerMobil/Models/MokMandator.cs b/BeWoPlanerMobil/Models/MokMandator.cs index 5840305ae..e9763de58 100644 --- a/BeWoPlanerMobil/Models/MokMandator.cs +++ b/BeWoPlanerMobil/Models/MokMandator.cs @@ -18,6 +18,7 @@ namespace BeWoPlanerMobil.Models //public string Website { get; set; } //public string PostalCode { get; set; } public string Settings { get; set; } + public string OwnChatCode { get; set; } //public string State { get; set; } //public string Street { get; set; } //public string Town { get; set; } diff --git a/BeWoPlanerMobil/Scripts/ownSoft-Scripts/view-scripts/main.js b/BeWoPlanerMobil/Scripts/ownSoft-Scripts/view-scripts/main.js index 46cafe6e3..22b0589ed 100644 --- a/BeWoPlanerMobil/Scripts/ownSoft-Scripts/view-scripts/main.js +++ b/BeWoPlanerMobil/Scripts/ownSoft-Scripts/view-scripts/main.js @@ -92,6 +92,7 @@ function changeGroupBookingFormEnableState(enableState) { "#gb-distance-input, " + "textarea, " + "#reset-button, " + + "#aivoice-button, " + "#create-button, " + "#gb-textbausteine-btn, " + "#gb-hours-minutes-dropdown-btn, " + @@ -116,6 +117,7 @@ function changeSingleBookingFormEnableState(enableState) { "#goals-button, " + "textarea, " + "#reset-button, " + + "#aivoice-button, " + "#create-button, " + "#statistics-button, " + "#timeFrameSelect, " + diff --git a/BeWoPlanerMobil/Views/Main/SingleBookingPartial.cshtml b/BeWoPlanerMobil/Views/Main/SingleBookingPartial.cshtml index 6167dcd2a..2df806ba4 100644 --- a/BeWoPlanerMobil/Views/Main/SingleBookingPartial.cshtml +++ b/BeWoPlanerMobil/Views/Main/SingleBookingPartial.cshtml @@ -168,6 +168,94 @@ } + + @using(Html.BeginForm("ResetSingleBookingForm", "Main", FormMethod.Post, new { Id = "reset-single-booking-form-form" })) { }
@@ -580,29 +668,47 @@
} -
- +
+ - @if(Model.IsInEditingMode) + @if (Model.IsInEditingMode) + { + using (Html.BeginForm("ResetEditingMode", "Main", FormMethod.Post)) { - using(Html.BeginForm("ResetEditingMode", "Main", FormMethod.Post)) - { - - } + } - else if(Model.IsInTransferMode) + } + else if (Model.IsInTransferMode) + { + using (Html.BeginForm("ResetTransferMode", "Main", FormMethod.Post)) { - using(Html.BeginForm("ResetTransferMode", "Main", FormMethod.Post)) - { - - } + } - else - { - - } - - @Html.Partial("RestoreServiceRecordInputsPartial", Model) + } + else + { + + } + + @if (Model.HasRightToUseAiVoice) + { + + } + + + + @Html.Partial("RestoreServiceRecordInputsPartial", Model) +
+ + @* Waiting-Overlay für externen Aufruf *@ + }
diff --git a/BeWoPlanerMobil/Views/Shared/_Layout.cshtml b/BeWoPlanerMobil/Views/Shared/_Layout.cshtml index 5f4a80288..da3499b27 100644 --- a/BeWoPlanerMobil/Views/Shared/_Layout.cshtml +++ b/BeWoPlanerMobil/Views/Shared/_Layout.cshtml @@ -55,7 +55,7 @@ - +