Added the simulation of the test situation to the sessions shared from the BeyondFacts Lab

This commit is contained in:
Thorsten Sommer committed 2026-11-15 16:36:23 +01:00
1 parent c08e5d7fb0
commit c11c5640c2
4 files changed
+40 -6

No files matched your search

@@ -144,8 +144,10 @@ public partial class BflShareDialog : MSGComponentBase
} }
var researchTopics = research.Where(entry => !string.IsNullOrWhiteSpace(entry.Value.Text)).Select(entry => entry.Key).ToList(); var researchTopics = research.Where(entry => !string.IsNullOrWhiteSpace(entry.Value.Text)).Select(entry => entry.Key).ToList();
var researchedPeople = BflStepResearch.Of(research, await this.Store.LoadAllPersonResearchAsync(this.ProjectId)).People.Count(person => person.Stages.Count > 0); var people = await this.Store.LoadAllPersonResearchAsync(this.ProjectId);
this.source = new BflShareInput(forms, workStates, results, conversations, materials, researchTopics, researchedPeople, false, APP_VERSION, DateTimeOffset.UtcNow, Culture, await this.LoadValueDeckAsync()); var researchedPeople = BflStepResearch.Of(research, people).People.Count(person => person.Stages.Count > 0);
var simulation = BflEffectiveSimulation.Of(forms.GetValueOrDefault(BflStep.TEST_SITUATION)?.Simulation, BflSimulationCandidates.Of(forms, research, people));
this.source = new BflShareInput(forms, workStates, results, conversations, materials, researchTopics, researchedPeople, false, APP_VERSION, DateTimeOffset.UtcNow, Culture, await this.LoadValueDeckAsync(), simulation);
this.otherNames = string.Join('\n', BflShareNames.Suggest(forms, workStates, research.GetValueOrDefault(BflResearchTopic.PARTICIPANTS))); this.otherNames = string.Join('\n', BflShareNames.Suggest(forms, workStates, research.GetValueOrDefault(BflResearchTopic.PARTICIPANTS)));
} }
catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or InvalidDataException) catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or InvalidDataException)
@@ -17,4 +17,5 @@ namespace AIStudio.Assistants.BeyondFactsLab;
/// <param name="SharedAtUtc">When the person shares the session.</param> /// <param name="SharedAtUtc">When the person shares the session.</param>
/// <param name="Culture">The culture for dates and numbers, the one of the language of the app.</param> /// <param name="Culture">The culture for dates and numbers, the one of the language of the app.</param>
/// <param name="ValueDeck">The value deck in the language of the app, with which the session shows the card sort of the person; null leaves the card sort out.</param> /// <param name="ValueDeck">The value deck in the language of the app, with which the session shows the card sort of the person; null leaves the card sort out.</param>
public sealed record BflShareInput(IReadOnlyDictionary<BflStep, BflStepFormData> Forms, IReadOnlyDictionary<BflStep, BflWorkState> WorkStates, IReadOnlyDictionary<BflResultKind, BflResult> Results, IReadOnlyDictionary<BflStep, IReadOnlyList<BflConversationMessage>> Conversations, IReadOnlyList<BflMaterial> Materials, IReadOnlyCollection<BflResearchTopic> ResearchTopics, int ResearchedPeople, bool IncludePersonalDisclosures, string AppVersion, DateTimeOffset SharedAtUtc, CultureInfo Culture, BflValueDeck? ValueDeck); /// <param name="Simulation">Whom the conversation of the step "Test situation" plays right now; only its mode and how many people it plays go into the session, never their names. Null counts as generic counterparts.</param>
public sealed record BflShareInput(IReadOnlyDictionary<BflStep, BflStepFormData> Forms, IReadOnlyDictionary<BflStep, BflWorkState> WorkStates, IReadOnlyDictionary<BflResultKind, BflResult> Results, IReadOnlyDictionary<BflStep, IReadOnlyList<BflConversationMessage>> Conversations, IReadOnlyList<BflMaterial> Materials, IReadOnlyCollection<BflResearchTopic> ResearchTopics, int ResearchedPeople, bool IncludePersonalDisclosures, string AppVersion, DateTimeOffset SharedAtUtc, CultureInfo Culture, BflValueDeck? ValueDeck, BflEffectiveSimulation? Simulation = null);
@@ -45,7 +45,8 @@ public static class BflShareModelBuilder
/// <summary> /// <summary>
/// Appends what the research team needs to read the session: the version of AI Studio, the date, how much material /// Appends what the research team needs to read the session: the version of AI Studio, the date, how much material
/// the person added, on which topics the lab researched, and how many people it researched in depth. /// the person added, on which topics the lab researched, how many people it researched in depth, and whom the test
/// situation simulates.
/// </summary> /// </summary>
/// <param name="text">The session so far.</param> /// <param name="text">The session so far.</param>
/// <param name="input">What the session is put together from.</param> /// <param name="input">What the session is put together from.</param>
@@ -62,9 +63,20 @@ public static class BflShareModelBuilder
AppendItem(text, TB("Material"), string.Format(input.Culture, TB("{0} documents, {1} recordings, {2} images"), documents, recordings, images)); AppendItem(text, TB("Material"), string.Format(input.Culture, TB("{0} documents, {1} recordings, {2} images"), documents, recordings, images));
AppendItem(text, TB("Research on the web"), topics.Count > 0 ? string.Join(", ", topics) : TB("none")); AppendItem(text, TB("Research on the web"), topics.Count > 0 ? string.Join(", ", topics) : TB("none"));
AppendItem(text, TB("People researched in depth"), input.ResearchedPeople.ToString(input.Culture)); AppendItem(text, TB("People researched in depth"), input.ResearchedPeople.ToString(input.Culture));
AppendItem(text, TB("Simulation in the test situation"), Simulation(input));
AppendItem(text, TB("Personal disclosures"), input.IncludePersonalDisclosures ? TB("included") : TB("left out")); AppendItem(text, TB("Personal disclosures"), input.IncludePersonalDisclosures ? TB("included") : TB("left out"));
} }
/// <summary>
/// Describes whom the test situation simulates: the mode and how many people, without their names.
/// </summary>
/// <param name="input">What the session is put together from.</param>
private static string Simulation(BflShareInput input)
{
var simulation = input.Simulation ?? BflEffectiveSimulation.GENERIC;
return simulation.People.Count is 0 ? simulation.Mode.Title : string.Format(input.Culture, TB("{0} ({1} simulated)"), simulation.Mode.Title, simulation.People.Count);
}
/// <summary> /// <summary>
/// Appends a step: its details, its confirmed work state, its conversation, and for the last step the confirmed /// Appends a step: its details, its confirmed work state, its conversation, and for the last step the confirmed
/// materials. /// materials.
@@ -179,6 +179,24 @@ public sealed class BflShareModelBuilderTests
} }
} }
[Test]
public void TheSimulationAppearsWithItsModeAndTheNumberOfPeopleButNoNames()
{
var research = new BflPersonResearch { Name = "Eva Klein" };
research.Set(BflPersonResearchStage.POSITIONS, new BflResearch { Text = "Positionen", CreatedAtUtc = NOW });
var simulation = new BflEffectiveSimulation(BflSimulationMode.PANEL_DISCUSSION, [new BflSimulatedPerson(new() { Name = "Eva Klein" }, research)]);
var withPeople = Build(simulation: simulation);
var generic = Build();
using (Assert.EnterMultipleScope())
{
Assert.That(withPeople, Does.Contain($"- **Simulation in the test situation:** {BflSimulationMode.PANEL_DISCUSSION.Title} (1 simulated)\n"));
Assert.That(withPeople, Does.Not.Contain("Eva Klein"));
Assert.That(generic, Does.Contain($"- **Simulation in the test situation:** {BflSimulationMode.GENERIC.Title}\n"));
}
}
[Test] [Test]
public void EveryStepAppearsInItsOrder() public void EveryStepAppearsInItsOrder()
{ {
@@ -237,7 +255,7 @@ public sealed class BflShareModelBuilderTests
Assert.That(Build(forms: forms, valueDeck: deck), Does.Not.Contain("Card sort")); Assert.That(Build(forms: forms, valueDeck: deck), Does.Not.Contain("Card sort"));
} }
private static string Build(Dictionary<BflStep, BflStepFormData>? forms = null, IReadOnlyDictionary<BflStep, BflWorkState>? workStates = null, IReadOnlyDictionary<BflResultKind, BflResult>? results = null, IReadOnlyDictionary<BflStep, IReadOnlyList<BflConversationMessage>>? conversations = null, IReadOnlyList<BflMaterial>? materials = null, IReadOnlyCollection<BflResearchTopic>? researchTopics = null, int researchedPeople = 0, bool includePersonalDisclosures = false, BflValueDeck? valueDeck = null) => BflShareModelBuilder.Build(new BflShareInput( private static string Build(Dictionary<BflStep, BflStepFormData>? forms = null, IReadOnlyDictionary<BflStep, BflWorkState>? workStates = null, IReadOnlyDictionary<BflResultKind, BflResult>? results = null, IReadOnlyDictionary<BflStep, IReadOnlyList<BflConversationMessage>>? conversations = null, IReadOnlyList<BflMaterial>? materials = null, IReadOnlyCollection<BflResearchTopic>? researchTopics = null, int researchedPeople = 0, bool includePersonalDisclosures = false, BflValueDeck? valueDeck = null, BflEffectiveSimulation? simulation = null) => BflShareModelBuilder.Build(new BflShareInput(
forms ?? Forms(), forms ?? Forms(),
workStates ?? new Dictionary<BflStep, BflWorkState>(), workStates ?? new Dictionary<BflStep, BflWorkState>(),
results ?? new Dictionary<BflResultKind, BflResult>(), results ?? new Dictionary<BflResultKind, BflResult>(),
@@ -249,7 +267,8 @@ public sealed class BflShareModelBuilderTests
"26.11.2", "26.11.2",
NOW, NOW,
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
valueDeck)); valueDeck,
simulation));
private static Dictionary<BflStep, BflStepFormData> Forms() => BflStep.All.ToDictionary(step => step, _ => new BflStepFormData()); private static Dictionary<BflStep, BflStepFormData> Forms() => BflStep.All.ToDictionary(step => step, _ => new BflStepFormData());