diff --git a/Assets/Scripts/VitrivrVR/Input/Text/SceneTextInputController.cs b/Assets/Scripts/VitrivrVR/Input/Text/SceneTextInputController.cs index e927458..8a0972d 100644 --- a/Assets/Scripts/VitrivrVR/Input/Text/SceneTextInputController.cs +++ b/Assets/Scripts/VitrivrVR/Input/Text/SceneTextInputController.cs @@ -1,7 +1,5 @@ using UnityEngine; -using VitrivrVR.Config; -using Dev.Dres.ClientApi.Model; -using VitrivrVR.Submission; +using VitrivrVR.Logging; namespace VitrivrVR.Input.Text { @@ -13,45 +11,43 @@ public class SceneTextInputController : MonoBehaviour public void InputText(string text) { TextInputManager.InputText(text); - DresClientManager.LogInteraction("keyboard", $"input {text}", QueryEvent.CategoryEnum.TEXT); + LoggingController.LogInteraction("keyboard", $"input {text}", Logging.Interaction.TextInput); } public void InputBackspace() { TextInputManager.InputBackspace(); - DresClientManager.LogInteraction("keyboard", "backspace", QueryEvent.CategoryEnum.TEXT); + LoggingController.LogInteraction("keyboard", "backspace", Logging.Interaction.TextInput); } - + public void InputReturn() { TextInputManager.InputReturn(); - DresClientManager.LogInteraction("keyboard", "return", QueryEvent.CategoryEnum.TEXT); + LoggingController.LogInteraction("keyboard", "return", Logging.Interaction.TextInput); } - + public void InputLeftArrow() { TextInputManager.InputLeftArrow(); - DresClientManager.LogInteraction("keyboard", "ArrowLeft", QueryEvent.CategoryEnum.TEXT); + LoggingController.LogInteraction("keyboard", "ArrowLeft", Logging.Interaction.TextInput); } - + public void InputRightArrow() { TextInputManager.InputRightArrow(); - DresClientManager.LogInteraction("keyboard", "ArrowRight", QueryEvent.CategoryEnum.TEXT); + LoggingController.LogInteraction("keyboard", "ArrowRight", Logging.Interaction.TextInput); } + public void InputTabulator() { TextInputManager.InputTabulator(); - DresClientManager.LogInteraction("keyboard", "Tabulator", QueryEvent.CategoryEnum.TEXT); + LoggingController.LogInteraction("keyboard", "Tabulator", Logging.Interaction.TextInput); } public void ReceiveDictationResult(string text) { InputText(text); - if (ConfigManager.Config.dresEnabled) - { - DresClientManager.LogInteraction("speechToText", $"input {text} DeepSpeech", QueryEvent.CategoryEnum.TEXT); - } + LoggingController.LogInteraction("speechToText", $"input {text} DeepSpeech", Logging.Interaction.TextInput); } } } \ No newline at end of file diff --git a/Assets/Scripts/VitrivrVR/Logging.meta b/Assets/Scripts/VitrivrVR/Logging.meta new file mode 100644 index 0000000..4d675af --- /dev/null +++ b/Assets/Scripts/VitrivrVR/Logging.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b037eb8c67aa944928d91bb3b60e1885 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/VitrivrVR/Logging/Interaction.cs b/Assets/Scripts/VitrivrVR/Logging/Interaction.cs new file mode 100644 index 0000000..b6635ce --- /dev/null +++ b/Assets/Scripts/VitrivrVR/Logging/Interaction.cs @@ -0,0 +1,14 @@ +namespace VitrivrVR.Logging +{ + public enum Interaction + { + TextInput, + QueryFormulation, + Query, + QueryManagement, + Browsing, + Filter, + ResultExpansion, + Other + } +} \ No newline at end of file diff --git a/Assets/Scripts/VitrivrVR/Logging/Interaction.cs.meta b/Assets/Scripts/VitrivrVR/Logging/Interaction.cs.meta new file mode 100644 index 0000000..12607da --- /dev/null +++ b/Assets/Scripts/VitrivrVR/Logging/Interaction.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 003cde0f439d406e8414b0f6020035d4 +timeCreated: 1669973631 \ No newline at end of file diff --git a/Assets/Scripts/VitrivrVR/Logging/LoggingController.cs b/Assets/Scripts/VitrivrVR/Logging/LoggingController.cs new file mode 100644 index 0000000..dde3976 --- /dev/null +++ b/Assets/Scripts/VitrivrVR/Logging/LoggingController.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Threading; +using Newtonsoft.Json; +using Org.Vitrivr.CineastApi.Model; +using Vitrivr.UnityInterface.CineastApi.Model.Data; +using VitrivrVR.Config; +using VitrivrVR.Notification; +using VitrivrVR.Submission; + +namespace VitrivrVR.Logging +{ + /// + /// Static class for all interaction and usage logs. + /// + /// The goal of this class is to separate the log sources from different kinds of loggers, such as file and + /// competition loggers. + /// + public static class LoggingController + { + private static readonly string StartDate = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"); + private static readonly string LogDir = Path.Combine(ConfigManager.Config.logFileLocation, StartDate); + private static readonly string ResultLogLocation = Path.Combine(LogDir, "results.txt"); + private static readonly string SubmissionLogLocation = Path.Combine(LogDir, "submission.txt"); + private static readonly string InteractionLogLocation = Path.Combine(LogDir, "interactions.txt"); + + private static readonly SemaphoreSlim SubmissionLogLock = new(1, 1); + private static readonly SemaphoreSlim ResultLogLock = new(1, 1); + private static readonly SemaphoreSlim InteractionLogLock = new(1, 1); + + private static long CurrentTimestamp => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + + /// + /// Logs ranked results lists for similarity and staged similarity queries. + /// + /// The order in which the ranked results are displayed (e.g. by segment or object). + /// List of ranked results. + /// Query response containing the source query. + public static void LogQueryResults(string sortOrder, List results, QueryResponse queryResponse) + { + var timestamp = CurrentTimestamp; + + // Log to DRES + if (ConfigManager.Config.dresEnabled) + { + // Similarity query + if (queryResponse.Query != null) + { + DresClientManager.LogResults(timestamp, sortOrder, results, queryResponse.Query); + } + + // Staged query + if (queryResponse.StagedQuery != null) + { + DresClientManager.LogResults(timestamp, sortOrder, results, queryResponse.StagedQuery); + } + } + + // Log to file + if (ConfigManager.Config.writeLogsToFile) + { + LogQueryResultsToFile(timestamp, sortOrder, results, queryResponse); + } + } + + /// + /// Logs ranked results lists for temporal similarity queries. + /// + public static void LogQueryResults(string sortOrder, List results, + TemporalQueryResponse queryResponse) + { + var timestamp = CurrentTimestamp; + + // Log to DRES + if (ConfigManager.Config.dresEnabled) + { + DresClientManager.LogResults(timestamp, sortOrder, results, queryResponse.Query); + } + + // Log to file + if (ConfigManager.Config.writeLogsToFile) + { + LogQueryResultsToFile(timestamp, sortOrder, results, queryResponse); + } + } + + public static void LogSubmission(string mediaObjectId, int? frame) + { + var timestamp = CurrentTimestamp; + // Log to file + if (ConfigManager.Config.writeLogsToFile) + { + LogSubmissionToFile(timestamp, mediaObjectId, frame); + } + } + + public static void LogInteraction(string type, string value, Interaction category) + { + var timestamp = CurrentTimestamp; + var source = new StackTrace().GetFrame(1).GetMethod().ReflectedType?.Name; + + // Log to DRES + if (ConfigManager.Config.dresEnabled) + { + DresClientManager.LogInteraction(timestamp, type, value, category); + } + + // Log to file + if (ConfigManager.Config.writeLogsToFile) + { + LogInteractionToFile(timestamp, source, type, value, category.ToString()); + } + } + + #region FileLogger + + private static void EnsureDirectoryExists() + { + Directory.CreateDirectory(LogDir); + } + + private static async void LogQueryResultsToFile(long timestamp, string sortOrder, + IEnumerable results, + QueryResponse queryResponse) + { + EnsureDirectoryExists(); + await ResultLogLock.WaitAsync(); + try + { + await using var file = new StreamWriter(ResultLogLocation, true); + var serializableResults = results.Select(segment => new Dictionary + { + { "id", segment.segment.Id }, + { "score", segment.score.ToString(CultureInfo.InvariantCulture) } + }); + var jsonResults = JsonConvert.SerializeObject(serializableResults, Formatting.None); + var jsonQuery = QueryToJson(queryResponse); + + var resultLog = + $"{{\"timestamp\":{timestamp},\"sortOrder\":\"{sortOrder}\",\"query\":{jsonQuery},\"results\":{jsonResults}}}"; + await file.WriteLineAsync(resultLog); + } + catch (Exception e) + { + NotificationController.NotifyError($"Error logging to file: {e.Message}", e); + } + finally + { + ResultLogLock.Release(); + } + } + + private static async void LogQueryResultsToFile(long timestamp, string sortOrder, List results, + TemporalQueryResponse queryResponse) + { + EnsureDirectoryExists(); + await ResultLogLock.WaitAsync(); + try + { + await using var file = new StreamWriter(ResultLogLocation, true); + var jsonResults = JsonConvert.SerializeObject(results, Formatting.None); + var jsonQuery = JsonConvert.SerializeObject(queryResponse.Query, Formatting.None); + + var resultLog = + $"{{\"timestamp\":{timestamp},\"sortOrder\":\"{sortOrder}\",\"query\":{jsonQuery},\"results\":{jsonResults}}}"; + await file.WriteLineAsync(resultLog); + } + catch (Exception e) + { + NotificationController.NotifyError($"Error logging to file: {e.Message}", e); + } + finally + { + ResultLogLock.Release(); + } + } + + private static string QueryToJson(QueryResponse queryResponse) + { + if (queryResponse.Query != null) + { + return JsonConvert.SerializeObject(queryResponse.Query, Formatting.None); + } + + if (queryResponse.StagedQuery != null) + { + return JsonConvert.SerializeObject(queryResponse.StagedQuery, Formatting.None); + } + + throw new Exception("Query response contains neither similarity nor staged similarity query."); + } + + private static async void LogSubmissionToFile(long timestamp, string mediaObjectId, int? frame) + { + EnsureDirectoryExists(); + await SubmissionLogLock.WaitAsync(); + try + { + await using var file = new StreamWriter(SubmissionLogLocation, true); + var dict = new Dictionary + { + { "timestamp", timestamp.ToString() }, + { "mediaObjectId", mediaObjectId } + }; + if (frame.HasValue) + dict["frame"] = frame.ToString(); + + var json = JsonConvert.SerializeObject(dict, Formatting.None); + + await file.WriteLineAsync(json); + } + catch (Exception e) + { + NotificationController.NotifyError($"Error logging to file: {e.Message}"); + } + finally + { + SubmissionLogLock.Release(); + } + } + + private static async void LogInteractionToFile(long timestamp, string source, string type, string value, + string category) + { + EnsureDirectoryExists(); + await InteractionLogLock.WaitAsync(); + try + { + await using var file = new StreamWriter(InteractionLogLocation, true); + var dict = new Dictionary + { + { "timestamp", timestamp.ToString() }, + { "source", source }, + { "type", type }, + { "value", value }, + { "category", category } + }; + + var json = JsonConvert.SerializeObject(dict, Formatting.None); + + await file.WriteLineAsync(json); + } + catch (Exception e) + { + NotificationController.NotifyError($"Error logging to file: {e.Message}"); + } + finally + { + InteractionLogLock.Release(); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Assets/Scripts/VitrivrVR/Logging/LoggingController.cs.meta b/Assets/Scripts/VitrivrVR/Logging/LoggingController.cs.meta new file mode 100644 index 0000000..34df72e --- /dev/null +++ b/Assets/Scripts/VitrivrVR/Logging/LoggingController.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 413dc264b46c4f46b6df685d1208687a +timeCreated: 1666274469 \ No newline at end of file diff --git a/Assets/Scripts/VitrivrVR/Media/Display/CanvasImageDisplay.cs b/Assets/Scripts/VitrivrVR/Media/Display/CanvasImageDisplay.cs index 714cdba..f82f19c 100644 --- a/Assets/Scripts/VitrivrVR/Media/Display/CanvasImageDisplay.cs +++ b/Assets/Scripts/VitrivrVR/Media/Display/CanvasImageDisplay.cs @@ -8,10 +8,12 @@ using Vitrivr.UnityInterface.CineastApi.Model.Data; using Vitrivr.UnityInterface.CineastApi.Model.Registries; using VitrivrVR.Config; +using VitrivrVR.Logging; using VitrivrVR.Notification; using VitrivrVR.Submission; using VitrivrVR.UI; using VitrivrVR.Util; +using static VitrivrVR.Logging.Interaction; namespace VitrivrVR.Media.Display { @@ -67,8 +69,10 @@ public override async void Initialize(ScoredSegment scoredSegment, Action onClos if (ConfigManager.Config.dresEnabled) { submitButton.SetActive(true); - DresClientManager.LogInteraction("imageSequenceDisplay", $"initialized {_mediaObject.Id} {Segment.Id}"); } + + LoggingController.LogInteraction("imageSequenceDisplay", $"initialized {_mediaObject.Id} {Segment.Id}", + ResultExpansion); } public void Close() @@ -79,7 +83,7 @@ public void Close() private void OnDestroy() { - DresClientManager.LogInteraction("imageDisplay", $"closed {_mediaObject.Id} {Segment.Id}"); + LoggingController.LogInteraction("imageDisplay", $"closed {_mediaObject.Id} {Segment.Id}", Other); } public async void ToggleMetadata() @@ -88,7 +92,7 @@ public async void ToggleMetadata() { Destroy(_metadataTable); _metadataShown = false; - DresClientManager.LogInteraction("mediaSegmentMetadata", $"closed {_mediaObject.Id}"); + LoggingController.LogInteraction("mediaSegmentMetadata", $"closed {_mediaObject.Id}", Other); return; } @@ -123,7 +127,7 @@ public async void ToggleMetadata() var uiTableTransform = _metadataTable.GetComponent(); uiTableTransform.sizeDelta = new Vector2(100, 600); // x is completely irrelevant here, since width is auto - DresClientManager.LogInteraction("mediaObjectMetadata", $"opened {_mediaObject.Id}"); + LoggingController.LogInteraction("mediaObjectMetadata", $"opened {_mediaObject.Id}", ResultExpansion); } public async void ToggleTagList() @@ -132,7 +136,7 @@ public async void ToggleTagList() { Destroy(_tagList.gameObject); _tagListShown = false; - DresClientManager.LogInteraction("segmentTags", $"closed {_mediaObject.Id}"); + LoggingController.LogInteraction("segmentTags", $"closed {_mediaObject.Id}", Other); return; } @@ -157,7 +161,7 @@ public async void ToggleTagList() tagItem.GetComponentInChildren().text = tagData.Name; } - DresClientManager.LogInteraction("segmentTags", $"opened {_mediaObject.Id} {Segment.Id}"); + LoggingController.LogInteraction("segmentTags", $"opened {_mediaObject.Id} {Segment.Id}", ResultExpansion); } public void Submit() diff --git a/Assets/Scripts/VitrivrVR/Media/Display/CanvasImageSequenceDisplay.cs b/Assets/Scripts/VitrivrVR/Media/Display/CanvasImageSequenceDisplay.cs index c79d276..5eee4d6 100644 --- a/Assets/Scripts/VitrivrVR/Media/Display/CanvasImageSequenceDisplay.cs +++ b/Assets/Scripts/VitrivrVR/Media/Display/CanvasImageSequenceDisplay.cs @@ -8,10 +8,12 @@ using Vitrivr.UnityInterface.CineastApi.Model.Data; using Vitrivr.UnityInterface.CineastApi.Model.Registries; using VitrivrVR.Config; +using VitrivrVR.Logging; using VitrivrVR.Notification; using VitrivrVR.Submission; using VitrivrVR.UI; using VitrivrVR.Util; +using static VitrivrVR.Logging.Interaction; namespace VitrivrVR.Media.Display { @@ -31,7 +33,7 @@ public class CanvasImageSequenceDisplay : MediaDisplay /// /// The number of neighbors to show in the segment view. /// - private const int MAXNeighbors = 200; + private const int MaxNeighbors = 200; private ScoredSegment _scoredSegment; private SegmentData Segment => _scoredSegment.segment; @@ -76,8 +78,10 @@ public override async void Initialize(ScoredSegment scoredSegment, Action onClos if (ConfigManager.Config.dresEnabled) { submitButton.SetActive(true); - DresClientManager.LogInteraction("imageSequenceDisplay", $"initialized {_mediaObject.Id} {Segment.Id}"); } + + LoggingController.LogInteraction("imageSequenceDisplay", $"initialized {_mediaObject.Id} {Segment.Id}", + ResultExpansion); } public void Close() @@ -93,7 +97,7 @@ private void OnDestroy() Destroy(_objectSegmentView); } - DresClientManager.LogInteraction("imageSequenceDisplay", $"closed {_mediaObject.Id} {Segment.Id}"); + LoggingController.LogInteraction("imageSequenceDisplay", $"closed {_mediaObject.Id} {Segment.Id}", Other); } public async void ToggleMetadata() @@ -102,7 +106,7 @@ public async void ToggleMetadata() { Destroy(_metadataTable); _metadataShown = false; - DresClientManager.LogInteraction("mediaSegmentMetadata", $"closed {_mediaObject.Id}"); + LoggingController.LogInteraction("mediaSegmentMetadata", $"closed {_mediaObject.Id}", Other); return; } @@ -137,7 +141,7 @@ public async void ToggleMetadata() var uiTableTransform = _metadataTable.GetComponent(); uiTableTransform.sizeDelta = new Vector2(100, 600); // x is completely irrelevant here, since width is auto - DresClientManager.LogInteraction("mediaObjectMetadata", $"opened {_mediaObject.Id}"); + LoggingController.LogInteraction("mediaObjectMetadata", $"opened {_mediaObject.Id}", ResultExpansion); } public async void ToggleTagList() @@ -146,7 +150,7 @@ public async void ToggleTagList() { Destroy(_tagList.gameObject); _tagListShown = false; - DresClientManager.LogInteraction("segmentTags", $"closed {_mediaObject.Id}"); + LoggingController.LogInteraction("segmentTags", $"closed {_mediaObject.Id}", Other); return; } @@ -171,7 +175,7 @@ public async void ToggleTagList() tagItem.GetComponentInChildren().text = tagData.Name; } - DresClientManager.LogInteraction("segmentTags", $"opened {_mediaObject.Id} {Segment.Id}"); + LoggingController.LogInteraction("segmentTags", $"opened {_mediaObject.Id} {Segment.Id}", ResultExpansion); } public async void ShowObjectSegmentView() @@ -183,8 +187,8 @@ public async void ShowObjectSegmentView() else { var index = await Segment.GetSequenceNumber(); - var min = index - MAXNeighbors; - var max = index + MAXNeighbors; + var min = index - MaxNeighbors; + var max = index + MaxNeighbors; var t = transform; _objectSegmentView = Instantiate(mediaObjectSegmentViewPrefab, t.position - 0.2f * t.forward, t.rotation); _objectSegmentView.GetComponentInChildren() diff --git a/Assets/Scripts/VitrivrVR/Media/Display/CanvasVideoDisplay.cs b/Assets/Scripts/VitrivrVR/Media/Display/CanvasVideoDisplay.cs index 6e72a50..4448191 100644 --- a/Assets/Scripts/VitrivrVR/Media/Display/CanvasVideoDisplay.cs +++ b/Assets/Scripts/VitrivrVR/Media/Display/CanvasVideoDisplay.cs @@ -15,12 +15,14 @@ using Vitrivr.UnityInterface.CineastApi.Model.Registries; using Vitrivr.UnityInterface.CineastApi.Utils; using VitrivrVR.Config; +using VitrivrVR.Logging; using VitrivrVR.Media.Controller; using VitrivrVR.Notification; using VitrivrVR.Query; using VitrivrVR.Submission; using VitrivrVR.UI; using VitrivrVR.Util; +using static VitrivrVR.Logging.Interaction; namespace VitrivrVR.Media.Display { @@ -116,8 +118,9 @@ public override async void Initialize(ScoredSegment segment, Action onClose) if (ConfigManager.Config.dresEnabled) { submitButton.SetActive(true); - DresClientManager.LogInteraction("videoPlayer", $"initialized {_mediaObject.Id} {_segment.Id}"); } + + LoggingController.LogInteraction("videoPlayer", $"initialized {_mediaObject.Id} {_segment.Id}", ResultExpansion); } public void Close() @@ -133,7 +136,7 @@ private void OnDestroy() Destroy(_objectSegmentView); } - DresClientManager.LogInteraction("videoPlayer", $"closed {_mediaObject.Id} {_segment.Id}"); + LoggingController.LogInteraction("videoPlayer", $"closed {_mediaObject.Id} {_segment.Id}", Other); } public void ShowObjectSegmentView() @@ -157,7 +160,7 @@ public async void ToggleMetadata() { Destroy(_metadataTable); _metadataShown = false; - DresClientManager.LogInteraction("mediaObjectMetadata", $"closed {_mediaObject.Id}"); + LoggingController.LogInteraction("mediaObjectMetadata", $"closed {_mediaObject.Id}", Other); return; } @@ -194,7 +197,7 @@ public async void ToggleMetadata() var uiTableTransform = _metadataTable.GetComponent(); uiTableTransform.sizeDelta = new Vector2(100, 600); // x is completely irrelevant here, since width is auto - DresClientManager.LogInteraction("mediaObjectMetadata", $"opened {_mediaObject.Id}"); + LoggingController.LogInteraction("mediaObjectMetadata", $"opened {_mediaObject.Id}", ResultExpansion); } public async void ToggleTagList() @@ -203,7 +206,7 @@ public async void ToggleTagList() { Destroy(_tagList.gameObject); _tagListShown = false; - DresClientManager.LogInteraction("segmentTags", $"closed {_mediaObject.Id}"); + LoggingController.LogInteraction("segmentTags", $"closed {_mediaObject.Id}", Other); return; } @@ -231,7 +234,7 @@ public async void ToggleTagList() tagItem.GetComponentInChildren().text = tagData.Name; } - DresClientManager.LogInteraction("segmentTags", $"opened {_mediaObject.Id} {segment.Id}"); + LoggingController.LogInteraction("segmentTags", $"opened {_mediaObject.Id} {segment.Id}", ResultExpansion); } public void SubmitCurrentFrame() @@ -244,7 +247,7 @@ public void SubmitCurrentFrame() var frame = _videoPlayerController.Frame; - DresClientManager.SubmitResult(_mediaObject.Id, (int) frame); + DresClientManager.SubmitResult(_mediaObject.Id, (int)frame); } public void SetVolume(float volume) @@ -256,7 +259,7 @@ public void QueryByCurrentFrame() { var frame = _videoPlayerController.GetCurrentFrame(); var term = QueryTermBuilder.BuildImageTermForCategories(frame, ConfigManager.Config.defaultImageCategories); - QueryController.Instance.RunQuery(new List {term}); + QueryController.Instance.RunQuery(new List { term }); } private void Awake() @@ -306,12 +309,12 @@ private void Skip(InputAction.CallbackContext context) UpdateText(time); } - DresClientManager.LogInteraction("videoPlayer", $"skipped {_mediaObject.Id} {time} {sign}"); + LoggingController.LogInteraction("videoPlayer", $"skipped {_mediaObject.Id} {time} {sign}", Browsing); } private void Update() { - if (_videoPlayerController is {IsPlaying: true}) + if (_videoPlayerController is { IsPlaying: true }) { var time = _videoPlayerController.ClockTime; UpdateProgressIndicator(time); @@ -324,12 +327,14 @@ public void OnClick(PointerEventData pointerEventData) if (_videoPlayerController.IsPlaying) { _videoPlayerController.Pause(); - DresClientManager.LogInteraction("videoPlayer", $"pause {_mediaObject.Id} {_videoPlayerController.ClockTime}"); + LoggingController.LogInteraction("videoPlayer", $"pause {_mediaObject.Id} {_videoPlayerController.ClockTime}", + Browsing); } else { _videoPlayerController.Play(); - DresClientManager.LogInteraction("videoPlayer", $"play {_mediaObject.Id} {_videoPlayerController.ClockTime}"); + LoggingController.LogInteraction("videoPlayer", $"play {_mediaObject.Id} {_videoPlayerController.ClockTime}", + Browsing); } } @@ -348,7 +353,8 @@ private void OnClickProgressBar(PointerEventData pointerEventData) UpdateProgressIndicator(newTime); UpdateText(newTime); - DresClientManager.LogInteraction("videoPlayer", $"jump {_mediaObject.Id} {newTime}"); + LoggingController.LogInteraction("videoPlayer", $"jump {_mediaObject.Id} {newTime}", + Browsing); } private void SetVideoTime(double time) @@ -420,7 +426,7 @@ private IEnumerator InstantiateSegmentIndicators(IEnumerable segmentStart var i = 0; foreach (var segStart in segmentStarts) { - progressTexture.SetPixel((int) (999 * (segStart / _videoPlayerController.Length)), 0, Color.black); + progressTexture.SetPixel((int)(999 * (segStart / _videoPlayerController.Length)), 0, Color.black); i++; if (i == InstantiationBatch) { @@ -442,7 +448,7 @@ private void ErrorEncountered(VideoPlayer videoPlayer, string error) private void UpdateProgressIndicator(double time) { progressIndicator.anchoredPosition = - new Vector2((float) (progressBar.rect.width * time / _videoPlayerController.Length), 0); + new Vector2((float)(progressBar.rect.width * time / _videoPlayerController.Length), 0); } private async void UpdateText(double time) @@ -476,8 +482,8 @@ private async Task GetCurrentSegment(double time) private void SetSegmentIndicator(double start, double end, double length, RectTransform rt) { var rect = progressBar.rect; - rt.anchoredPosition = new Vector2((float) (rect.width * start / length), 0); - rt.sizeDelta = new Vector2((float) (rect.width * (end - start) / length), 0); + rt.anchoredPosition = new Vector2((float)(rect.width * start / length), 0); + rt.sizeDelta = new Vector2((float)(rect.width * (end - start) / length), 0); } } } \ No newline at end of file diff --git a/Assets/Scripts/VitrivrVR/Media/Display/MediaObjectSegmentView.cs b/Assets/Scripts/VitrivrVR/Media/Display/MediaObjectSegmentView.cs index 61e29df..9e801a3 100644 --- a/Assets/Scripts/VitrivrVR/Media/Display/MediaObjectSegmentView.cs +++ b/Assets/Scripts/VitrivrVR/Media/Display/MediaObjectSegmentView.cs @@ -8,8 +8,9 @@ using Vitrivr.UnityInterface.CineastApi.Model.Data; using VitrivrVR.Interaction.System; using VitrivrVR.Interaction.System.Grab; +using VitrivrVR.Logging; using VitrivrVR.Media.Controller; -using VitrivrVR.Submission; +using static VitrivrVR.Logging.Interaction; namespace VitrivrVR.Media.Display { @@ -42,7 +43,8 @@ private void OnTriggerEnter(Collider other) if (other.TryGetComponent(out var interactor)) { _enteredInteractors.Add(interactor, -1); - DresClientManager.LogInteraction("videoSummary", $"browse started {_mediaObject.Id}"); + LoggingController.LogInteraction("videoSummary", $"browse started {_mediaObject.Id} {interactor.name}", + Browsing); } } @@ -57,7 +59,8 @@ private void OnTriggerExit(Collider other) } _enteredInteractors.Remove(interactor); - DresClientManager.LogInteraction("videoSummary", $"browse stopped {_mediaObject.Id}"); + LoggingController.LogInteraction("videoSummary", $"browse stopped {_mediaObject.Id} {interactor.name}", + Browsing); } } @@ -87,7 +90,7 @@ private void OnTriggerExit(Collider other) private void OnDestroy() { - DresClientManager.LogInteraction("videoSummary", $"closed {_mediaObject.Id}"); + LoggingController.LogInteraction("videoSummary", $"closed {_mediaObject.Id}", Other); } public async void Initialize(ObjectData mediaObject, Action onSegmentSelection, int min = 0, @@ -116,7 +119,7 @@ await Task.WhenAll(segments.Select(async segment => StartCoroutine(InstantiateSegmentIndicators(segmentInfo, segmentInfo.Length)); // TODO: Translate type in DresClientManager to support other media object types - DresClientManager.LogInteraction("videoSummary", $"initialized {_mediaObject.Id}"); + LoggingController.LogInteraction("videoSummary", $"initialized {_mediaObject.Id}", ResultExpansion); } public override void OnInteraction(Transform interactor, bool start) @@ -125,7 +128,8 @@ public override void OnInteraction(Transform interactor, bool start) var rawIndex = GetSegmentIndex(interactor); var segmentIndex = rawIndex + _minIndex - 1; _onSegmentSelection(segmentIndex, interactor.position); - DresClientManager.LogInteraction("videoSummary", $"selected {_mediaObject.Id} {segmentIndex}"); + LoggingController.LogInteraction("videoSummary", $"selected {_mediaObject.Id} {segmentIndex} {interactor.name}", + ResultExpansion); } private IEnumerator InstantiateSegmentIndicators(IEnumerable<(SegmentData segment, int seqNum)> segmentInfo, @@ -139,7 +143,7 @@ private IEnumerator InstantiateSegmentIndicators(IEnumerable<(SegmentData segmen var thumbnail = Instantiate(thumbnailPrefab, transform); thumbnail.url = thumbnailUrl; - thumbnail.transform.localPosition = Vector3.forward * ((float) (seqNum - _minIndex) / numSegments - 0.5f); + thumbnail.transform.localPosition = Vector3.forward * ((float)(seqNum - _minIndex) / numSegments - 0.5f); _thumbnails[seqNum - _minIndex] = thumbnail; @@ -192,7 +196,7 @@ private void SetThumbnailHeight(int index, bool selected) private int GetSegmentIndex(Transform other) { var otherTransform = transform.InverseTransformPoint(other.position); - return (int) Mathf.Min(Mathf.Max((otherTransform.z + 0.5f) * _thumbnails.Length, 0), _thumbnails.Length - 1); + return (int)Mathf.Min(Mathf.Max((otherTransform.z + 0.5f) * _thumbnails.Length, 0), _thumbnails.Length - 1); } } } \ No newline at end of file diff --git a/Assets/Scripts/VitrivrVR/Query/Display/CylinderObjectQueryDisplay.cs b/Assets/Scripts/VitrivrVR/Query/Display/CylinderObjectQueryDisplay.cs index 17aa41d..3700a80 100644 --- a/Assets/Scripts/VitrivrVR/Query/Display/CylinderObjectQueryDisplay.cs +++ b/Assets/Scripts/VitrivrVR/Query/Display/CylinderObjectQueryDisplay.cs @@ -2,13 +2,14 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Vitrivr.UnityInterface.CineastApi.Model.Data; using UnityEngine; using UnityEngine.InputSystem; +using Vitrivr.UnityInterface.CineastApi.Model.Data; using VitrivrVR.Config; +using VitrivrVR.Logging; using VitrivrVR.Media.Display; using VitrivrVR.Notification; -using VitrivrVR.Submission; +using static VitrivrVR.Logging.Interaction; namespace VitrivrVR.Query.Display { @@ -106,17 +107,7 @@ protected override void Initialize() _enqueued++; } - if (ConfigManager.Config.dresEnabled) - { - if (queryData.Query != null) - { - DresClientManager.LogResults("segment", _results, queryData.Query); - } - else - { - DresClientManager.LogResults("segment", _results, queryData.StagedQuery); - } - } + LoggingController.LogQueryResults("object", _results, queryData); } /// @@ -156,6 +147,8 @@ private void Rotate(float degrees) _currentStart = enabledStart; _currentEnd = enabledEnd; + + LoggingController.LogInteraction("rankedList", $"browse {Mathf.Sign(degrees)}", Browsing); } } @@ -181,7 +174,7 @@ private async Task CreateResultObject(ScoredSegment result) else { _objectMap[objectId] = _mediaObjectSegmentDisplays.Count; - _mediaObjectSegmentDisplays.Add(new List {itemDisplay}); + _mediaObjectSegmentDisplays.Add(new List { itemDisplay }); } var index = _objectMap[objectId]; diff --git a/Assets/Scripts/VitrivrVR/Query/Display/CylinderQueryDisplay.cs b/Assets/Scripts/VitrivrVR/Query/Display/CylinderQueryDisplay.cs index e6f9471..ddc6534 100644 --- a/Assets/Scripts/VitrivrVR/Query/Display/CylinderQueryDisplay.cs +++ b/Assets/Scripts/VitrivrVR/Query/Display/CylinderQueryDisplay.cs @@ -1,13 +1,14 @@ using System; using System.Collections.Generic; using System.Linq; -using Vitrivr.UnityInterface.CineastApi.Model.Data; using UnityEngine; using UnityEngine.InputSystem; +using Vitrivr.UnityInterface.CineastApi.Model.Data; using VitrivrVR.Config; +using VitrivrVR.Logging; using VitrivrVR.Media.Display; using VitrivrVR.Notification; -using VitrivrVR.Submission; +using static VitrivrVR.Logging.Interaction; namespace VitrivrVR.Query.Display { @@ -27,9 +28,9 @@ public class CylinderQueryDisplay : QueryDisplay public override int NumberOfResults => _nResults; - private readonly List _mediaDisplays = new List(); + private readonly List _mediaDisplays = new(); - private readonly Queue _instantiationQueue = new Queue(); + private readonly Queue _instantiationQueue = new(); private List _results; @@ -90,17 +91,7 @@ protected override void Initialize() _instantiationQueue.Enqueue(segment); } - if (ConfigManager.Config.dresEnabled) - { - if (queryData.Query != null) - { - DresClientManager.LogResults("segment", _results, queryData.Query); - } - else - { - DresClientManager.LogResults("segment", _results, queryData.StagedQuery); - } - } + LoggingController.LogQueryResults("segment", _results, queryData); } /// @@ -140,7 +131,7 @@ private void Rotate(float degrees) _currentStart = enabledStart; _currentEnd = enabledEnd; - DresClientManager.LogInteraction("rankedList", $"browse {Mathf.Sign(degrees)}"); + LoggingController.LogInteraction("rankedList", $"browse {Mathf.Sign(degrees)}", Browsing); } } diff --git a/Assets/Scripts/VitrivrVR/Query/Display/CylinderTemporalQueryDisplay.cs b/Assets/Scripts/VitrivrVR/Query/Display/CylinderTemporalQueryDisplay.cs index 0deab95..aa6dc7e 100644 --- a/Assets/Scripts/VitrivrVR/Query/Display/CylinderTemporalQueryDisplay.cs +++ b/Assets/Scripts/VitrivrVR/Query/Display/CylinderTemporalQueryDisplay.cs @@ -5,9 +5,10 @@ using UnityEngine; using UnityEngine.InputSystem; using VitrivrVR.Config; +using VitrivrVR.Logging; using VitrivrVR.Media.Display; using VitrivrVR.Notification; -using VitrivrVR.Submission; +using static VitrivrVR.Logging.Interaction; namespace VitrivrVR.Query.Display { @@ -74,7 +75,7 @@ private void Update() protected override void Initialize() { _results = temporalQueryData.Results.Content; - + if (_results.Count == 0) { NotificationController.Notify("No results returned from query!"); @@ -86,10 +87,7 @@ protected override void Initialize() _instantiationQueue.Enqueue(temporalObject); } - if (ConfigManager.Config.dresEnabled) - { - DresClientManager.LogResults("temporal", _results, temporalQueryData.Query); - } + LoggingController.LogQueryResults("temporal", _results, temporalQueryData); } /// @@ -129,7 +127,7 @@ private void Rotate(float degrees) _currentStart = enabledStart; _currentEnd = enabledEnd; - DresClientManager.LogInteraction("rankedList", $"browse {Mathf.Sign(degrees)}"); + LoggingController.LogInteraction("rankedList", $"browse {Mathf.Sign(degrees)}", Browsing); } } diff --git a/Assets/Scripts/VitrivrVR/Query/QueryController.cs b/Assets/Scripts/VitrivrVR/Query/QueryController.cs index 95c4b4b..782850c 100644 --- a/Assets/Scripts/VitrivrVR/Query/QueryController.cs +++ b/Assets/Scripts/VitrivrVR/Query/QueryController.cs @@ -1,17 +1,18 @@ using System; using System.Collections.Generic; using System.Linq; -using Vitrivr.UnityInterface.CineastApi; -using Vitrivr.UnityInterface.CineastApi.Utils; using Org.Vitrivr.CineastApi.Model; using UnityEngine; using UnityEngine.Events; +using Vitrivr.UnityInterface.CineastApi; using Vitrivr.UnityInterface.CineastApi.Model.Data; +using Vitrivr.UnityInterface.CineastApi.Utils; using VitrivrVR.Config; +using VitrivrVR.Logging; using VitrivrVR.Notification; using VitrivrVR.Query.Display; using VitrivrVR.Query.Term; -using VitrivrVR.Submission; +using static VitrivrVR.Logging.Interaction; namespace VitrivrVR.Query { @@ -97,7 +98,7 @@ public void RunQuery(QueryTermManager queryTermManager) RunQuery(stages.First()); return; } - + // With stages RunQuery(stages); return; @@ -184,7 +185,7 @@ public async void RunQuery(List> stages) timer.transform.localRotation = Quaternion.identity; timer.SetActive(false); } - + public async void RunQuery(List>> temporalTerms) { var localGuid = Guid.NewGuid(); @@ -242,7 +243,7 @@ public void SelectQuery(int index) queryFocusEvent.Invoke(CurrentQuery, index); CurrentQuery = index; - DresClientManager.LogInteraction("queryManagement", $"select {index}"); + LoggingController.LogInteraction("queryManagement", $"select {index}", QueryManagement); } /// @@ -279,7 +280,7 @@ public void RemoveQuery(int index) queryRemovedEvent.Invoke(index); Destroy(queries[index].gameObject); queries.RemoveAt(index); - DresClientManager.LogInteraction("queryManagement", $"delete {index}"); + LoggingController.LogInteraction("queryManagement", $"delete {index}", QueryManagement); } public void RemoveAllQueries() @@ -296,7 +297,7 @@ public void ClearQuery() SetQueryActive(CurrentQuery, false); queryFocusEvent.Invoke(CurrentQuery, -1); CurrentQuery = -1; - DresClientManager.LogInteraction("queryManagement", "clear"); + LoggingController.LogInteraction("queryManagement", "clear", QueryManagement); } /// @@ -342,7 +343,7 @@ private void InstantiateQueryDisplay(QueryResponse queryData) queryFocusEvent.Invoke(CurrentQuery, queryIndex); CurrentQuery = queryIndex; } - + private void InstantiateQueryDisplay(TemporalQueryResponse queryData) { if (CurrentQuery != -1) diff --git a/Assets/Scripts/VitrivrVR/Submission/DresClientManager.cs b/Assets/Scripts/VitrivrVR/Submission/DresClientManager.cs index 152808a..d398a05 100644 --- a/Assets/Scripts/VitrivrVR/Submission/DresClientManager.cs +++ b/Assets/Scripts/VitrivrVR/Submission/DresClientManager.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Net; using System.Threading.Tasks; @@ -12,46 +11,33 @@ using Vitrivr.UnityInterface.CineastApi.Model.Data; using Vitrivr.UnityInterface.CineastApi.Model.Registries; using VitrivrVR.Config; +using VitrivrVR.Logging; using VitrivrVR.Notification; +using static Dev.Dres.ClientApi.Model.QueryEvent; namespace VitrivrVR.Submission { public class DresClientManager : MonoBehaviour { - public static DresClient Instance; + private static DresClient _instance; private static readonly List InteractionEvents = new(); private static float _interactionEventTimer; - private static string _interactionLogPath; - private static string _resultsLogPath; - private static string _submissionLogPath; - private async void Start() { if (!ConfigManager.Config.dresEnabled) return; if (ConfigManager.Config.allowInvalidCertificate) { - ServicePointManager.ServerCertificateValidationCallback += - (sender, certificate, chain, sslPolicyErrors) => true; + ServicePointManager.ServerCertificateValidationCallback += (_, _, _, _) => true; + // (sender, certificate, chain, sslPolicyErrors) => true; } - Instance = new DresClient(); - await Instance.Login(); - var logDir = ConfigManager.Config.logFileLocation; - var startTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - var username = Instance.UserDetails.Username; - var session = Instance.UserDetails.SessionId; - _interactionLogPath = Path.Combine(logDir, $"{startTime}_{username}_{session}_interaction.txt"); - _resultsLogPath = Path.Combine(logDir, $"{startTime}_{username}_{session}_results.txt"); - _submissionLogPath = Path.Combine(logDir, $"{startTime}_{username}_{session}_submission.txt"); - NotificationController.Notify($"Dres connected: {username}"); - - if (ConfigManager.Config.writeLogsToFile) - { - Directory.CreateDirectory(ConfigManager.Config.logFileLocation); - } + _instance = new DresClient(); + await _instance.Login(); + var username = _instance.UserDetails.Username; + NotificationController.Notify($"DRES connected: {username}"); } private void Update() @@ -78,7 +64,7 @@ public static async void SubmitResult(string mediaObjectId, int? frame = null) try { - var result = await Instance.SubmitResult(mediaObjectId, frame); + var result = await _instance.SubmitResult(mediaObjectId, frame); NotificationController.Notify($"Submission: {result.Submission}"); } catch (Exception e) @@ -86,10 +72,7 @@ public static async void SubmitResult(string mediaObjectId, int? frame = null) NotificationController.Notify(e.Message); } - if (ConfigManager.Config.writeLogsToFile) - { - LogSubmissionToFile(mediaObjectId, frame); - } + LoggingController.LogSubmission(mediaObjectId, frame); } /// @@ -119,33 +102,17 @@ public static async void QuickSubmitSegment(SegmentData segment) } } - private static async void LogSubmissionToFile(string mediaObjectId, int? frame) - { - var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - try - { - await using var file = new StreamWriter(_submissionLogPath, true); - var row = $"{timestamp},{mediaObjectId}"; - if (frame != null) - row += $",{frame}"; - await file.WriteLineAsync(row); - } - catch (Exception e) - { - NotificationController.Notify($"Error logging to file: {e.Message}"); - } - } - /// - /// Logs results to the connected Dres instance. + /// Logs results to the connected DRES instance. /// /// The sorting of the results display. /// The results as list of scored segments. /// The query that lead to these results represented as enumerable of query events. /// Timestamp of result log. /// Skips trying to batch fetch segment data if true. - public static async void LogResults(string sortType, List<(ScoredSegment segment, int rank)> results, - IEnumerable queryEvents, long timestamp, bool assumeFullyFetched = false) + private static async void LogResults(string sortType, + IReadOnlyCollection<(ScoredSegment segment, int rank)> results, IEnumerable queryEvents, + long timestamp, bool assumeFullyFetched = false) { if (!assumeFullyFetched) { @@ -167,7 +134,7 @@ public static async void LogResults(string sortType, List<(ScoredSegment segment var queryEventsList = queryEvents.ToList(); try { - var success = await Instance.LogResults(timestamp, sortType, "top", queryResultsList, queryEventsList); + var success = await _instance.LogResults(timestamp, sortType, "top", queryResultsList, queryEventsList); if (!success.Status) { @@ -178,31 +145,14 @@ public static async void LogResults(string sortType, List<(ScoredSegment segment { NotificationController.Notify(e.Message); } - - if (ConfigManager.Config.writeLogsToFile) - { - try - { - using var file = new StreamWriter(_resultsLogPath, true); - var jsonResults = string.Join(",", queryResultsList.Select(q => q.ToJson().Replace("\n", ""))); - var jsonEvents = string.Join(",", queryEventsList.Select(q => q.ToJson().Replace("\n", ""))); - var resultLog = $"{timestamp},{sortType},top,[{jsonResults}],[{jsonEvents}]"; - await file.WriteLineAsync(resultLog); - } - catch (Exception e) - { - NotificationController.NotifyError($"Error logging to file: {e.Message}", e); - } - } } - public static void LogResults(string sortType, IEnumerable results, SimilarityQuery query) + public static void LogResults(long timestamp, string sortType, IEnumerable results, + SimilarityQuery query) { - var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - var queryEvents = query.Terms.Select(term => { - // Convert term type to Dres category + // Convert term type to DRES category var category = TermTypeToDresCategory(term.Type); var type = string.Join(",", term.Categories.Select(CategoryToType)); @@ -216,19 +166,19 @@ public static void LogResults(string sortType, IEnumerable result LogResults(sortType, rankedResults, queryEvents, timestamp); } - public static void LogResults(string sortType, IEnumerable results, StagedSimilarityQuery query) + public static void LogResults(long timestamp, string sortType, IEnumerable results, + StagedSimilarityQuery query) { - var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - - var queryEvents = query.Stages.SelectMany(stage => stage.Terms.Select(term => + var queryEvents = query.Stages.SelectMany((stage, si) => stage.Terms.Select(term => { - // Convert term type to Dres category + // Convert term type to DRES category var category = TermTypeToDresCategory(term.Type); var type = string.Join(",", term.Categories.Select(CategoryToType)); var value = term.Data; - return new QueryEvent(timestamp, category, type, value); + // Also provide stage index in type + return new QueryEvent(timestamp, category, $"{si}:{type}", value); })); var rankedResults = results.Select((segment, rank) => (segment, rank)).ToList(); @@ -236,15 +186,14 @@ public static void LogResults(string sortType, IEnumerable result LogResults(sortType, rankedResults, queryEvents, timestamp); } - public static void LogResults(string sortType, IEnumerable results, TemporalQuery query) + public static void LogResults(long timestamp, string sortType, IEnumerable results, + TemporalQuery query) { - var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - var queryEvents = query.Queries.SelectMany( (temporal, ti) => temporal.Stages.SelectMany( (stage, si) => stage.Terms.Select(term => { - // Convert term type to Dres category + // Convert term type to DRES category var category = TermTypeToDresCategory(term.Type); var type = string.Join(",", term.Categories.Select(CategoryToType)); @@ -274,7 +223,7 @@ private static async void LogInteraction() // Submit to DRES try { - var success = await Instance.LogQueryEvents(timestamp, InteractionEvents); + var success = await _instance.LogQueryEvents(timestamp, InteractionEvents); if (!success.Status) { @@ -286,34 +235,14 @@ private static async void LogInteraction() NotificationController.NotifyError($"Error logging interaction: {e.Message}", e); } - var events = InteractionEvents.ToArray(); InteractionEvents.Clear(); - - // Write to file - if (ConfigManager.Config.writeLogsToFile) - { - try - { - using var file = new StreamWriter(_interactionLogPath, true); - foreach (var interactionEvent in events) - { - await file.WriteLineAsync(interactionEvent.ToJson().Replace("\n", "")); - } - } - catch (Exception e) - { - NotificationController.NotifyError($"Error logging to file: {e.Message}", e); - } - } } - public static void LogInteraction(string type, string value, - QueryEvent.CategoryEnum category = QueryEvent.CategoryEnum.BROWSING) + public static void LogInteraction(long timestamp, string type, string value, Logging.Interaction category) { if (!ConfigManager.Config.dresEnabled) return; - var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - var queryEvent = new QueryEvent(timestamp, category, type, value); + var queryEvent = new QueryEvent(timestamp, InteractionToDresCategory(category), type, value); InteractionEvents.Add(queryEvent); } @@ -338,21 +267,37 @@ private static string CategoryToType(string category) }; } - private static QueryEvent.CategoryEnum TermTypeToDresCategory(QueryTerm.TypeEnum? type) + private static CategoryEnum TermTypeToDresCategory(QueryTerm.TypeEnum? type) { return type switch { - QueryTerm.TypeEnum.IMAGE => QueryEvent.CategoryEnum.IMAGE, - QueryTerm.TypeEnum.AUDIO => QueryEvent.CategoryEnum.OTHER, - QueryTerm.TypeEnum.MODEL3D => QueryEvent.CategoryEnum.OTHER, - QueryTerm.TypeEnum.LOCATION => QueryEvent.CategoryEnum.OTHER, - QueryTerm.TypeEnum.TIME => QueryEvent.CategoryEnum.OTHER, - QueryTerm.TypeEnum.TEXT => QueryEvent.CategoryEnum.TEXT, - QueryTerm.TypeEnum.TAG => QueryEvent.CategoryEnum.TEXT, - QueryTerm.TypeEnum.SEMANTIC => QueryEvent.CategoryEnum.SKETCH, - QueryTerm.TypeEnum.ID => QueryEvent.CategoryEnum.OTHER, - QueryTerm.TypeEnum.BOOLEAN => QueryEvent.CategoryEnum.FILTER, - _ => QueryEvent.CategoryEnum.OTHER + QueryTerm.TypeEnum.IMAGE => CategoryEnum.IMAGE, + QueryTerm.TypeEnum.AUDIO => CategoryEnum.OTHER, + QueryTerm.TypeEnum.MODEL3D => CategoryEnum.OTHER, + QueryTerm.TypeEnum.LOCATION => CategoryEnum.OTHER, + QueryTerm.TypeEnum.TIME => CategoryEnum.OTHER, + QueryTerm.TypeEnum.TEXT => CategoryEnum.TEXT, + QueryTerm.TypeEnum.TAG => CategoryEnum.TEXT, + QueryTerm.TypeEnum.SEMANTIC => CategoryEnum.SKETCH, + QueryTerm.TypeEnum.ID => CategoryEnum.OTHER, + QueryTerm.TypeEnum.BOOLEAN => CategoryEnum.FILTER, + _ => CategoryEnum.OTHER + }; + } + + private static CategoryEnum InteractionToDresCategory(Logging.Interaction category) + { + return category switch + { + Logging.Interaction.TextInput => CategoryEnum.TEXT, + Logging.Interaction.Browsing => CategoryEnum.BROWSING, + Logging.Interaction.ResultExpansion => CategoryEnum.BROWSING, + Logging.Interaction.QueryFormulation => CategoryEnum.OTHER, + Logging.Interaction.Query => CategoryEnum.OTHER, + Logging.Interaction.Filter => CategoryEnum.FILTER, + Logging.Interaction.Other => CategoryEnum.OTHER, + Logging.Interaction.QueryManagement => CategoryEnum.BROWSING, + _ => throw new ArgumentOutOfRangeException(nameof(category), category, null) }; } @@ -362,7 +307,7 @@ private static QueryEvent.CategoryEnum TermTypeToDresCategory(QueryTerm.TypeEnum private static string RemovePrefix(string id) { var prefixLength = ConfigManager.Config.submissionIdPrefixLength; - return prefixLength > 0 ? id.Substring(prefixLength) : id; + return prefixLength > 0 ? id[prefixLength..] : id; } } } \ No newline at end of file