Added results and exports to the BeyondFacts Lab (#1184)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-11-10 13:54:10 +01:00
1 parent 8e1a66cb24
commit e5c0931a60
42 files changed
+3034 -67

No files matched your search

@@ -152,9 +152,20 @@
WorkStates="@this.workStates"
Forms="@this.forms"
FormChanged="@(() => this.SaveFormAsync(this.activeStep))"
WorkStateStored="@this.WorkStateStoredAsync"
WorkStateStored="@this.ProjectStoredAsync"
Provider="@this.providerSettings"
ProviderIssue="@this.ValidateProvider(this.providerSettings)"/>
@if (this.activeStep is BflStep.RESULTS)
{
<BflResults ProjectId="@project.ProjectId"
ProjectName="@project.Name"
WorkStates="@this.workStates"
Forms="@this.forms"
ResultStored="@this.ProjectStoredAsync"
Provider="@this.providerSettings"
ProviderIssue="@this.ValidateProvider(this.providerSettings)"/>
}
</div>
</MudItem>
<MudItem xs="12" lg="4">
@@ -46,10 +46,10 @@ public partial class BeyondFactsLabAssistant
}
/// <summary>
/// Shows a work state after the panel of its step stored it.
/// Shows the new time of change of a preparation after a work state or a result of it was stored.
/// </summary>
/// <param name="project">The preparation with its new time of change.</param>
private Task WorkStateStoredAsync(BflProject project)
private Task ProjectStoredAsync(BflProject project)
{
this.ReplaceProject(project);
return Task.CompletedTask;
@@ -10,6 +10,7 @@ namespace AIStudio.Assistants.BeyondFactsLab;
[JsonSerializable(typeof(BflStepFormData))]
[JsonSerializable(typeof(BflMaterial))]
[JsonSerializable(typeof(BflWorkState))]
[JsonSerializable(typeof(BflResult))]
// The preparation selected last:
[JsonSerializable(typeof(Guid?))]
@@ -0,0 +1,129 @@
using System.Text.Json;
namespace AIStudio.Assistants.BeyondFactsLab;
public sealed partial class BeyondFactsLabStore
{
/// <summary>
/// The folder of a preparation which holds its results, one file for each kind.
/// </summary>
private const string RESULTS_DIRECTORY_NAME = "results";
/// <summary>
/// Loads a result of a preparation.
/// </summary>
/// <param name="projectId">The ID of the preparation.</param>
/// <param name="kind">The kind of result.</param>
/// <param name="token">The cancellation token.</param>
/// <returns>The result, or an empty one while the preparation has none.</returns>
/// <exception cref="InvalidDataException">This version cannot open the result.</exception>
public async Task<BflResult> LoadResultAsync(Guid projectId, BflResultKind kind, CancellationToken token = default)
{
await this.InitializeAsync(token);
return await this.LoadResultWithoutInitializeAsync(projectId, kind, token);
}
/// <summary>
/// Loads every result of a preparation.
/// </summary>
/// <param name="projectId">The ID of the preparation.</param>
/// <param name="token">The cancellation token.</param>
/// <returns>The results this version can open, by their kinds.</returns>
public async Task<IReadOnlyDictionary<BflResultKind, BflResult>> LoadResultsAsync(Guid projectId, CancellationToken token = default)
{
await this.InitializeAsync(token);
var results = new Dictionary<BflResultKind, BflResult>();
foreach (var kind in BflResultKind.All)
{
try
{
results[kind] = await this.LoadResultWithoutInitializeAsync(projectId, kind, token);
}
catch (InvalidDataException exception)
{
logger.LogWarning(exception, "Could not open the result '{Kind}' of the preparation '{ProjectId}' of the BeyondFacts Lab.", kind, projectId);
}
}
return results;
}
/// <summary>
/// Stores a result of a preparation and counts it as a change of the preparation.
/// </summary>
/// <param name="projectId">The ID of the preparation.</param>
/// <param name="kind">The kind of result.</param>
/// <param name="result">The result.</param>
/// <param name="token">The cancellation token.</param>
/// <returns>The preparation with its new time of change.</returns>
/// <exception cref="FileNotFoundException">The preparation does not exist.</exception>
/// <exception cref="InvalidDataException">This version cannot open the preparation or the stored result, so it does not write them either.</exception>
public async Task<BflProject> SaveResultAsync(Guid projectId, BflResultKind kind, BflResult result, CancellationToken token = default)
{
await this.InitializeAsync(token);
var gate = this.GetLock(projectId);
await gate.WaitAsync(token);
try
{
var project = await this.LoadRequiredWithoutInitializeAsync(projectId, token);
// A result which a newer version stored, or which is damaged, stays as it is:
await this.LoadResultWithoutInitializeAsync(projectId, kind, token);
result.SchemaVersion = BflResult.CURRENT_SCHEMA_VERSION;
await WriteTextAtomicAsync(this.ResultPath(projectId, kind), JsonSerializer.Serialize(result, JSON_OPTIONS), token);
project.ModifiedAtUtc = DateTimeOffset.UtcNow;
await this.StoreProjectAsync(project, token);
return project;
}
finally
{
gate.Release();
}
}
/// <summary>
/// Reads a result of a preparation without the first start of the store.
/// </summary>
/// <param name="projectId">The ID of the preparation.</param>
/// <param name="kind">The kind of result.</param>
/// <param name="token">The cancellation token.</param>
/// <returns>The result, or an empty one when there is no file.</returns>
/// <exception cref="InvalidDataException">This version cannot open the result.</exception>
private async Task<BflResult> LoadResultWithoutInitializeAsync(Guid projectId, BflResultKind kind, CancellationToken token)
{
var path = this.ResultPath(projectId, kind);
if (!File.Exists(path))
return new BflResult();
BflResult? result;
try
{
await using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 65_536, true);
result = await JsonSerializer.DeserializeAsync<BflResult>(stream, JSON_OPTIONS, token);
}
catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or JsonException)
{
throw new InvalidDataException("This version of AI Studio cannot open the result.", exception);
}
if (result is null || result.SchemaVersion is < 1 or > BflResult.CURRENT_SCHEMA_VERSION || !IsReadable(result.Draft) || !IsReadable(result.Confirmed))
throw new InvalidDataException("This version of AI Studio cannot open the result.");
return result;
}
/// <summary>
/// Tells whether a version of a result, which may be missing, has everything this version of AI Studio reads.
/// </summary>
/// <param name="version">The version, or null.</param>
private static bool IsReadable(BflResultVersion? version) => version is null || !IsNull(version.Text) && !IsNull(version.WorkStateRevisions);
/// <summary>
/// Gets the file of a result of a preparation.
/// </summary>
/// <param name="projectId">The ID of the preparation.</param>
/// <param name="kind">The kind of result.</param>
private string ResultPath(Guid projectId, BflResultKind kind) => Path.Combine(this.ProjectDirectory(projectId), RESULTS_DIRECTORY_NAME, kind.FileName);
}
@@ -0,0 +1,8 @@
namespace AIStudio.Assistants.BeyondFactsLab;
/// <summary>
/// A message of a conversation in the lab as the person saw it, e.g., for the appendix of the reflection folder.
/// </summary>
/// <param name="IsFromPerson">Whether the person wrote the message; otherwise, the lab did.</param>
/// <param name="Text">The text of the message, in Markdown.</param>
public sealed record BflConversationMessage(bool IsFromPerson, string Text);
@@ -0,0 +1,50 @@
using AIStudio.Chat;
using AIStudio.Provider;
namespace AIStudio.Assistants.BeyondFactsLab;
/// <summary>
/// Sends a request which the person never sees, in a hidden copy of a conversation of the lab, e.g., for a work state
/// or a result.
/// </summary>
/// <remarks>
/// The copy carries the system prompt and the messages of the conversation, so the model knows all the step knows.
/// The lab never stores it, and the conversation itself stays as it is.
/// </remarks>
public static class BflHiddenRequest
{
/// <summary>
/// Sends a request in the hidden copy of a conversation and waits for the whole answer.
/// </summary>
/// <param name="hidden">The hidden copy of the conversation, which keeps the request and the answer.</param>
/// <param name="provider">The provider which answers.</param>
/// <param name="text">The request.</param>
/// <param name="images">The images of the material, which go along with the first message.</param>
/// <param name="token">The cancellation token.</param>
/// <returns>The answer, empty when the provider failed.</returns>
public static async Task<string> AskAsync(ChatThread hidden, AIStudio.Settings.Provider provider, string text, IReadOnlyList<FileAttachmentImage> images, CancellationToken token)
{
var request = new ContentText { Text = text };
hidden.Blocks.Add(new ContentBlock
{
Time = DateTimeOffset.Now,
ContentType = ContentType.TEXT,
Role = ChatRole.USER,
Content = request,
HideFromUser = true
});
var answer = new ContentText { InitialRemoteWait = true };
hidden.Blocks.Add(new ContentBlock
{
Time = DateTimeOffset.Now,
ContentType = ContentType.TEXT,
Role = ChatRole.AI,
Content = answer,
HideFromUser = true
});
await answer.CreateFromProviderAsync(provider.CreateProvider(), provider.Model, request, BflConversationService.WithImages(hidden, images), token);
return answer.Text;
}
}
@@ -40,6 +40,9 @@
<MudListItem T="string" Icon="@Icons.Material.Filled.Looks6" Style="@LIST_ITEM_STYLE">
<MudJustifiedText Typo="Typo.body1">@TA("Once a step is largely clear, let the lab create its work state below the conversation. You check and edit it, and once you confirm it, the later steps build on it. The lab also suggests values for empty fields of 'Your details', which you take over one by one.")</MudJustifiedText>
</MudListItem>
<MudListItem T="string" Icon="@Icons.Material.Filled.TaskAlt" Style="@LIST_ITEM_STYLE">
<MudJustifiedText Typo="Typo.body1">@TA("In the last step, let the lab create your materials from your confirmed work states: a reflection folder, a position paper, a conversation guide, questions and answers, and your open points. You check, edit, and confirm each of them, and then export it as a document.")</MudJustifiedText>
</MudListItem>
</MudList>
<MudText Typo="Typo.h6">@T("How to recognize good results")</MudText>
@@ -71,6 +71,29 @@ public static class BflPromptComposer
[BflPromptTemplate.FIELDS] = SuggestableFields(step, form)
}).ReplaceLineEndings(LINE_BREAK.ToString()).Trim();
/// <summary>
/// Puts together the request which lets the model write a result, at the end of a hidden copy of the conversation
/// of the last step.
/// </summary>
/// <param name="template">The request, see BflPromptLibrary.ResultPath.</param>
/// <param name="workStates">The work states of the preparation, by their steps, to name the steps without a confirmed one.</param>
/// <returns>The request.</returns>
/// <exception cref="FormatException">The request has a placeholder without a value.</exception>
public static string ComposeResultRequest(string template, IReadOnlyDictionary<BflStep, BflWorkState> workStates) => BflPromptTemplate.Fill(template, new Dictionary<string, string>(StringComparer.Ordinal)
{
[BflPromptTemplate.MISSING_WORK_STATES] = MissingWorkStates(workStates)
}).ReplaceLineEndings(LINE_BREAK.ToString()).Trim();
/// <summary>
/// Names the steps without a confirmed work state, in their order.
/// </summary>
/// <param name="workStates">The work states of the preparation, by their steps.</param>
private static string MissingWorkStates(IReadOnlyDictionary<BflStep, BflWorkState> workStates)
{
var missing = BflStep.All.Where(step => workStates.GetValueOrDefault(step)?.Confirmed is null).Select(step => $"„{step.Title}“").ToList();
return missing.Count is 0 ? "keine; alle Schritte sind bestätigt." : $"{string.Join(", ", missing)}.";
}
/// <summary>
/// Puts together the request which asks the model once to correct the sections of a work state.
/// </summary>
@@ -40,6 +40,11 @@ public static class BflPromptLibrary
/// </summary>
public const string WORK_STATE_PATH = FOLDER + "/Prompts/work-state.md";
/// <summary>
/// The folder of the requests which let the model write a result, one for each kind a model writes.
/// </summary>
private const string RESULTS_FOLDER = FOLDER + "/Prompts/results/";
/// <summary>
/// The instruction to address the person formally.
/// </summary>
@@ -77,6 +82,12 @@ public static class BflPromptLibrary
BflPromptTemplate.SECTIONS,
BflPromptTemplate.FIELDS);
/// <summary>
/// The placeholders BflPromptComposer fills in the request for a result.
/// </summary>
private static readonly FrozenSet<string> RESULT_PLACEHOLDERS = FrozenSet.Create(StringComparer.Ordinal,
BflPromptTemplate.MISSING_WORK_STATES);
/// <summary>
/// The placeholders of every other file: none, because BflPromptComposer inserts these files as values.
/// </summary>
@@ -88,6 +99,21 @@ public static class BflPromptLibrary
/// <param name="step">The step.</param>
public static string StepPath(BflStep step) => $"{FOLDER}/Prompts/steps/{step.FolderName}.md";
/// <summary>
/// Gets the request which lets the model write a result.
/// </summary>
/// <param name="kind">The kind of result, one a model writes.</param>
/// <exception cref="ArgumentOutOfRangeException">No model writes this kind of result.</exception>
public static string ResultPath(BflResultKind kind) => kind switch
{
BflResultKind.POSITION_PAPER => RESULTS_FOLDER + "position-paper.md",
BflResultKind.CONVERSATION_GUIDE => RESULTS_FOLDER + "conversation-guide.md",
BflResultKind.QUESTIONS_AND_ANSWERS => RESULTS_FOLDER + "questions-and-answers.md",
BflResultKind.OPEN_POINTS => RESULTS_FOLDER + "open-points.md",
_ => throw new ArgumentOutOfRangeException(nameof(kind), kind, "No model writes this result.")
};
/// <summary>
/// Gets the instruction for a form of address.
/// </summary>
@@ -103,6 +129,7 @@ public static class BflPromptLibrary
KNOWLEDGE_PATH,
ONBOARDING_PATH,
WORK_STATE_PATH,
..BflResultKind.All.Where(kind => kind.IsWrittenByModel).Select(ResultPath),
..Enum.GetValues<AddressForm>().Select(AddressPath).Distinct(),
..BflStep.All.Select(StepPath)
];
@@ -118,9 +145,9 @@ public static class BflPromptLibrary
/// Gets the placeholders a file of the lab's prompts may contain.
/// </summary>
/// <remarks>
/// BflPromptComposer fills placeholders in the core, in the prompt of the onboarding, and in the request for a work
/// state only. It inserts every other file as a value, whose placeholders it leaves as they are, so that they would
/// reach the model as text.
/// BflPromptComposer fills placeholders in the core, in the prompt of the onboarding, and in the requests for a work
/// state and for a result only. It inserts every other file as a value, whose placeholders it leaves as they are, so
/// that they would reach the model as text.
/// </remarks>
/// <param name="path">The file, one of the paths of this class.</param>
public static IReadOnlySet<string> PlaceholdersOf(string path) => path switch
@@ -128,6 +155,7 @@ public static class BflPromptLibrary
CORE_PATH => CORE_PLACEHOLDERS,
ONBOARDING_PATH => ONBOARDING_PLACEHOLDERS,
WORK_STATE_PATH => WORK_STATE_PLACEHOLDERS,
_ when path.StartsWith(RESULTS_FOLDER, StringComparison.Ordinal) => RESULT_PLACEHOLDERS,
_ => NO_PLACEHOLDERS
};
@@ -62,6 +62,11 @@ public static partial class BflPromptTemplate
/// </summary>
public const string FIELDS = "FIELDS";
/// <summary>
/// The steps without a confirmed work state, whose topics a result must not fill with guesses.
/// </summary>
public const string MISSING_WORK_STATES = "MISSING_WORK_STATES";
/// <summary>
/// Fills every placeholder of a template.
/// </summary>
@@ -0,0 +1,188 @@
using System.Text;
using AIStudio.Chat;
namespace AIStudio.Assistants.BeyondFactsLab;
/// <summary>
/// Puts the reflection folder of a preparation together: all confirmed work states, the open questions, the material,
/// and, if the person likes, the conversations of the steps.
/// </summary>
/// <remarks>
/// No model takes part. The person confirmed every work state word for word, so the folder repeats them word for word
/// instead of having a model rewrite them. A step without a confirmed work state is named, not filled. Personal
/// disclosures stay out unless the person includes them, and so does the conversation of a step which may contain
/// some: the folder is meant to be passed on.
/// </remarks>
public static class BflReflectionFolder
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(BflReflectionFolder).Namespace, nameof(BflReflectionFolder));
private static string TA(string fallbackEN) => Tools.PluginSystem.I18N.I.TA(fallbackEN, typeof(BflReflectionFolder).Namespace, nameof(BflReflectionFolder));
/// <summary>
/// The key of the section of every step which holds its open points; the folder gathers them in one place.
/// </summary>
private const string OPEN_POINTS_KEY = "OPEN_POINTS";
/// <summary>
/// Puts the reflection folder together.
/// </summary>
/// <param name="input">What the folder is put together from.</param>
/// <returns>The folder, in Markdown.</returns>
public static string Build(BflReflectionFolderInput input)
{
var text = new StringBuilder();
text.Append("# ").Append(Markdown.EscapeInlineText(BflResultKind.REFLECTION_FOLDER.Title)).Append(": ").AppendLine(Markdown.EscapeInlineText(input.ProjectName));
foreach (var step in BflStep.All)
AppendStep(text, step, input);
AppendOpenPoints(text, input);
AppendMaterials(text, input);
if (input.Conversations.Count > 0)
AppendConversations(text, input);
return text.ToString().TrimEnd() + "\n";
}
/// <summary>
/// Gets the messages of a conversation as the person saw them.
/// </summary>
/// <remarks>
/// Hidden messages stay out, such as the request with which the lab opens a conversation, and so does everything
/// but text.
/// </remarks>
/// <param name="thread">The conversation.</param>
/// <returns>The visible messages with text, in their order.</returns>
public static IReadOnlyList<BflConversationMessage> MessagesOf(ChatThread thread) =>
[
.. thread.Blocks
.Where(block => !block.HideFromUser && block.Role is ChatRole.USER or ChatRole.AI)
.Select(block => block.Content is ContentText { Text: var messageText } && !string.IsNullOrWhiteSpace(messageText) ? new BflConversationMessage(block.Role is ChatRole.USER, messageText.Trim()) : null)
.OfType<BflConversationMessage>()
];
/// <summary>
/// Tells whether a step may hold personal disclosures, in its work state or in its form, so that its conversation
/// may contain them too.
/// </summary>
/// <param name="step">The step.</param>
public static bool MayHoldPersonalDisclosures(BflStep step) => BflWorkStateSections.ForStep(step).Any(section => section.IsPersonalDisclosure) || BflFieldCatalog.ForStep(step).Any(field => field.IsPersonalDisclosure);
/// <summary>
/// Appends the confirmed work state of a step, without its open points.
/// </summary>
/// <param name="text">The folder so far.</param>
/// <param name="step">The step.</param>
/// <param name="input">What the folder is put together from.</param>
private static void AppendStep(StringBuilder text, BflStep step, BflReflectionFolderInput input)
{
text.AppendLine().Append("## ").AppendLine(Markdown.EscapeInlineText(step.Title)).AppendLine();
if (input.WorkStates.GetValueOrDefault(step)?.Confirmed is not { } confirmed)
{
text.Append('_').Append(Markdown.EscapeInlineText(TB("No confirmed work state."))).AppendLine("_");
return;
}
var confirmedAt = confirmed.ConfirmedAtUtc.ToLocalTime().ToString("d", input.Culture);
text.Append('_').Append(Markdown.EscapeInlineText(string.Format(input.Culture, TB("Version {0}, confirmed on {1}."), confirmed.Revision, confirmedAt))).AppendLine("_");
var notice = BflStaleness.Of(step, input.WorkStates, input.Forms) switch
{
BflWorkStateStatus.OUTDATED => TB("An earlier step changed after this confirmation."),
BflWorkStateStatus.DETAILS_CHANGED => TB("The details of this step changed after this confirmation."),
_ => string.Empty
};
if (notice.Length > 0)
text.AppendLine().Append('_').Append(Markdown.EscapeInlineText(notice)).AppendLine("_");
foreach (var section in BflWorkStateSections.ForStep(step))
{
if (section.Key is OPEN_POINTS_KEY || section.IsPersonalDisclosure && !input.IncludePersonalDisclosures || !confirmed.Sections.TryGetValue(section.Key, out var sectionText) || string.IsNullOrWhiteSpace(sectionText))
continue;
text.AppendLine().Append("### ").AppendLine(Markdown.EscapeInlineText(section.Title)).AppendLine().AppendLine(sectionText.Trim());
}
}
/// <summary>
/// Appends the open points of all confirmed work states, by their steps.
/// </summary>
/// <param name="text">The folder so far.</param>
/// <param name="input">What the folder is put together from.</param>
private static void AppendOpenPoints(StringBuilder text, BflReflectionFolderInput input)
{
text.AppendLine().Append("## ").AppendLine(Markdown.EscapeInlineText(TB("Open questions"))).AppendLine();
var any = false;
foreach (var step in BflStep.All)
{
if (input.WorkStates.GetValueOrDefault(step)?.Confirmed?.Sections.GetValueOrDefault(OPEN_POINTS_KEY) is not { } openPoints || string.IsNullOrWhiteSpace(openPoints))
continue;
any = true;
text.Append("### ").AppendLine(Markdown.EscapeInlineText(step.Title)).AppendLine().AppendLine(openPoints.Trim()).AppendLine();
}
if (!any)
text.Append('_').Append(Markdown.EscapeInlineText(TB("No confirmed work state names open questions."))).AppendLine("_");
}
/// <summary>
/// Appends the list of the material.
/// </summary>
/// <param name="text">The folder so far.</param>
/// <param name="input">What the folder is put together from.</param>
private static void AppendMaterials(StringBuilder text, BflReflectionFolderInput input)
{
text.AppendLine().Append("## ").AppendLine(Markdown.EscapeInlineText(TB("Material"))).AppendLine();
if (input.Materials.Count is 0)
{
text.Append('_').Append(Markdown.EscapeInlineText(TB("No material was added."))).AppendLine("_");
return;
}
foreach (var material in input.Materials.OrderBy(material => material.AddedAtUtc))
text.Append("- ").Append(Markdown.EscapeInlineText(material.Name)).Append(" (").Append(Markdown.EscapeInlineText(KindName(material.Kind))).AppendLine(")");
}
/// <summary>
/// Appends the conversations of the steps as an appendix.
/// </summary>
/// <param name="text">The folder so far.</param>
/// <param name="input">What the folder is put together from.</param>
private static void AppendConversations(StringBuilder text, BflReflectionFolderInput input)
{
text.AppendLine().Append("## ").AppendLine(Markdown.EscapeInlineText(TB("Appendix: the conversations"))).AppendLine();
foreach (var step in BflStep.All)
{
if (!input.Conversations.TryGetValue(step, out var messages) || messages.Count is 0)
continue;
text.Append("### ").AppendLine(Markdown.EscapeInlineText(step.Title)).AppendLine();
if (!input.IncludePersonalDisclosures && MayHoldPersonalDisclosures(step))
{
text.Append('_').Append(Markdown.EscapeInlineText(TB("Left out, as it may contain personal disclosures."))).AppendLine("_").AppendLine();
continue;
}
foreach (var message in messages)
{
var speaker = message.IsFromPerson ? TA("You") : TB("Lab");
text.Append("**").Append(Markdown.EscapeInlineText(speaker)).AppendLine(":**").AppendLine().AppendLine(message.Text).AppendLine();
}
}
}
/// <summary>
/// Gets the name of a kind of material.
/// </summary>
/// <param name="kind">The kind of material.</param>
private static string KindName(BflMaterialKind kind) => kind switch
{
BflMaterialKind.DOCUMENT => TB("Document"),
BflMaterialKind.RECORDING => TB("Recording"),
BflMaterialKind.IMAGE => TB("Image"),
_ => TB("Material")
};
}
@@ -0,0 +1,15 @@
using System.Globalization;
namespace AIStudio.Assistants.BeyondFactsLab;
/// <summary>
/// What the reflection folder of a preparation is put together from.
/// </summary>
/// <param name="ProjectName">The name of the preparation.</param>
/// <param name="WorkStates">The work states of the preparation, by their steps; a step which is missing has none.</param>
/// <param name="Forms">The forms of the preparation, by their steps, to tell where a work state stands.</param>
/// <param name="Materials">The material of the preparation which can be opened.</param>
/// <param name="Conversations">The conversations of the steps, by their steps, for the appendix; empty for none.</param>
/// <param name="IncludePersonalDisclosures">Whether personal disclosures go into the folder, e.g., how the topic touches the person.</param>
/// <param name="Culture">The culture for dates, the one of the language of the app.</param>
public sealed record BflReflectionFolderInput(string ProjectName, IReadOnlyDictionary<BflStep, BflWorkState> WorkStates, IReadOnlyDictionary<BflStep, BflStepFormData> Forms, IReadOnlyList<BflMaterial> Materials, IReadOnlyDictionary<BflStep, IReadOnlyList<BflConversationMessage>> Conversations, bool IncludePersonalDisclosures, CultureInfo Culture);
@@ -0,0 +1,70 @@
namespace AIStudio.Assistants.BeyondFactsLab;
/// <summary>
/// A result of a preparation, such as the position paper, stored in the folder "results" of the preparation.
/// </summary>
/// <remarks>
/// The lab writes a draft, which the person reads, edits, and confirms; only a confirmed result can be exported. Like
/// a work state, a result keeps its confirmed version while the person works on a new draft. Whether it is outdated
/// is computed from the work states it was built from, see BflStaleness.IsOutdated.
/// </remarks>
public sealed class BflResult
{
/// <summary>
/// The version of the stored form this version of AI Studio writes. Raise it with every new property.
/// </summary>
public const int CURRENT_SCHEMA_VERSION = 1;
/// <summary>
/// Gets or sets the version of the stored form.
/// </summary>
public int SchemaVersion { get; set; } = CURRENT_SCHEMA_VERSION;
/// <summary>
/// Gets or sets the draft the person has not confirmed yet, or null while there is none.
/// </summary>
public BflResultVersion? Draft { get; set; }
/// <summary>
/// Gets or sets the version the person confirmed, or null while there is none.
/// </summary>
public BflResultVersion? Confirmed { get; set; }
/// <summary>
/// Starts a draft from the confirmed version, so that the person can edit it; a draft which is there already
/// stays as it is.
/// </summary>
public void Edit()
{
if (this.Draft is not null || this.Confirmed is not { } confirmed)
return;
this.Draft = new BflResultVersion
{
Text = confirmed.Text,
WorkStateRevisions = new(confirmed.WorkStateRevisions),
ChangedAtUtc = confirmed.ChangedAtUtc,
};
}
/// <summary>
/// Confirms the draft with the text the person approved: it becomes the version to export, and the draft is gone.
/// </summary>
/// <param name="text">The text of the draft as the person approved it.</param>
/// <param name="confirmedAtUtc">When the person confirmed it.</param>
/// <exception cref="InvalidOperationException">There is no draft to confirm.</exception>
public void Confirm(string text, DateTimeOffset confirmedAtUtc)
{
if (this.Draft is not { } draft)
throw new InvalidOperationException("There is no draft of the result to confirm.");
this.Confirmed = new BflResultVersion
{
Text = text,
WorkStateRevisions = new(draft.WorkStateRevisions),
ChangedAtUtc = confirmedAtUtc,
};
this.Draft = null;
}
}
@@ -0,0 +1,251 @@
using AIStudio.Provider;
using AIStudio.Tools.AssistantSessions;
namespace AIStudio.Assistants.BeyondFactsLab;
/// <summary>
/// Writes the drafts of the results of a preparation: the model writes four of them, and the reflection folder is put
/// together without a model.
/// </summary>
/// <remarks>
/// The model writes in a hidden copy of the conversation of the last step, with its system prompt, so it knows the
/// details, the material, and the confirmed work states of all steps; the person never sees the request, and the chat
/// stays as it is. Like the conversations, a singleton, so that the work goes on while the person looks at another
/// page. Nothing a draft says leaves AI Studio before the person confirms and exports it.
/// </remarks>
/// <param name="store">The store of the lab.</param>
/// <param name="conversations">The conversations of the lab, whose prompts and checks the results share.</param>
/// <param name="sessionService">The registry of running assistant sessions.</param>
/// <param name="messageBus">The message bus, for errors.</param>
/// <param name="logger">The logger.</param>
public sealed class BflResultGenerator(BeyondFactsLabStore store, BflConversationService conversations, AssistantSessionService sessionService, MessageBus messageBus, ILogger<BflResultGenerator> logger)
{
private static string TA(string fallbackEN) => Tools.PluginSystem.I18N.I.TA(fallbackEN, typeof(BflResultGenerator).Namespace, nameof(BflResultGenerator));
/// <summary>
/// The results the model writes right now.
/// </summary>
private readonly HashSet<BflResultLocation> running = [];
/// <summary>
/// Guards the results the model writes right now.
/// </summary>
private readonly Lock runningLock = new();
/// <summary>
/// Happens when the model starts or ends writing a result, and when a new draft is stored.
/// </summary>
/// <remarks>
/// Called on the thread of the request. A page renders through InvokeAsync.
/// </remarks>
public event Func<BflResultLocation, Task>? ResultChanged;
/// <summary>
/// Tells whether the model writes a result right now.
/// </summary>
/// <param name="location">The result.</param>
public bool IsRunning(BflResultLocation location)
{
lock (this.runningLock)
return this.running.Contains(location);
}
/// <summary>
/// Lets the model write the draft of a result and stores it, replacing an earlier draft.
/// </summary>
/// <remarks>
/// What goes wrong is reported through the message bus; the method itself does not fail. A confirmed result stays
/// as it is until the person confirms the new draft.
/// </remarks>
/// <param name="location">The result, one a model writes.</param>
/// <param name="provider">The provider which writes the result.</param>
public async Task GenerateAsync(BflResultLocation location, AIStudio.Settings.Provider provider)
{
if (!location.Kind.IsWrittenByModel)
return;
var stepLocation = new BflStepThreadLocation(location.ProjectId, BflStep.RESULTS);
var conversation = await conversations.GetAsync(stepLocation);
if (conversation.Thread is not { } thread || conversation.IsRunning || !await conversations.CheckProviderAsync(stepLocation, thread, provider))
return;
lock (this.runningLock)
{
if (!this.running.Add(location))
return;
}
var sessionKey = SessionKey(location);
var sessionId = Guid.Empty;
var status = AssistantSessionStatus.FAILED;
try
{
var workStates = await store.LoadWorkStatesAsync(location.ProjectId);
var revisions = BflStaleness.ConfirmedRevisionsOf(workStates);
var requestMaterial = await conversations.ComposeRequestAsync(stepLocation, provider);
var template = await BflPromptLibrary.ReadAsync(BflPromptLibrary.ResultPath(location.Kind), conversations.PromptOverridesDirectory);
var request = BflPromptComposer.ComposeResultRequest(template, workStates);
// A copy of the conversation, which the person never sees and the lab never stores:
var hidden = thread with { Blocks = [.. thread.Blocks] };
BflThreadFactory.PrepareForRequest(hidden, provider, requestMaterial.SystemPrompt);
var cancellation = new CancellationTokenSource();
sessionId = (await sessionService.TryBeginAsync(sessionKey, Tools.Components.BEYOND_FACTS_LAB_ASSISTANT.Name, cancellation, null, new(StringComparer.Ordinal))).SessionId;
await this.NotifyAsync(location);
var text = BflResultText.Read(await BflHiddenRequest.AskAsync(hidden, provider, request, requestMaterial.Images, cancellation.Token));
if (cancellation.IsCancellationRequested)
{
status = AssistantSessionStatus.CANCELED;
return;
}
if (text.Length is 0)
{
logger.LogWarning("The model wrote no text for the result '{Location}' of the BeyondFacts Lab.", location.Key);
await messageBus.SendError(new(Icons.Material.Filled.ErrorOutline, TA("The model did not write this material. Please try again, or try another provider.")));
return;
}
await this.StoreDraftAsync(location, text, revisions);
status = AssistantSessionStatus.COMPLETED;
}
catch (OperationCanceledException)
{
status = AssistantSessionStatus.CANCELED;
}
catch (BflPromptOverrideException exception)
{
logger.LogWarning(exception, "A prompt override of the BeyondFacts Lab has a placeholder which the lab does not fill.");
await messageBus.SendError(new(Icons.Material.Filled.ErrorOutline, string.Format(TA("The file '{0}' in the test folder of the BeyondFacts Lab contains the placeholder '{1}', which the lab does not fill in this file. Please correct the file and try again."), exception.FileName, exception.Placeholder)));
}
catch (ProviderRequestException exception)
{
logger.LogError(exception, "The provider request for a result of the BeyondFacts Lab failed. Status={StatusCode}, Reason='{ReasonPhrase}'.", exception.StatusCode, exception.ReasonPhrase);
await messageBus.SendError(new(Icons.Material.Filled.CloudOff, exception.UserMessage));
}
catch (FileNotFoundException)
{
// The person deleted the preparation while the model wrote; nothing is left to store.
}
catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or InvalidDataException or FormatException)
{
logger.LogError(exception, "The BeyondFacts Lab could not write the result '{Location}'.", location.Key);
await messageBus.SendError(new(Icons.Material.Filled.SaveAs, TA("AI Studio could not create this material. Please try again.")));
}
finally
{
lock (this.runningLock)
this.running.Remove(location);
if (sessionId != Guid.Empty)
{
await sessionService.CompleteAsync(sessionKey, sessionId, status, string.Empty, null, new(StringComparer.Ordinal));
await sessionService.ClearAsync(sessionKey);
}
await this.NotifyAsync(location);
}
}
/// <summary>
/// Puts the reflection folder of a preparation together and stores it as a draft, replacing an earlier draft.
/// </summary>
/// <remarks>
/// What goes wrong is reported through the message bus; the method itself does not fail.
/// </remarks>
/// <param name="projectId">The ID of the preparation.</param>
/// <param name="projectName">The name of the preparation.</param>
/// <param name="forms">The forms of the preparation, by their steps, to tell where a work state stands.</param>
/// <param name="includePersonalDisclosures">Whether personal disclosures go into the folder.</param>
/// <param name="includeConversations">Whether the conversations of the steps go into the folder as an appendix.</param>
public async Task AssembleReflectionFolderAsync(Guid projectId, string projectName, IReadOnlyDictionary<BflStep, BflStepFormData> forms, bool includePersonalDisclosures, bool includeConversations)
{
var location = new BflResultLocation(projectId, BflResultKind.REFLECTION_FOLDER);
try
{
var workStates = await store.LoadWorkStatesAsync(projectId);
var materials = (await store.ListMaterialsAsync(projectId)).Select(entry => entry.Material).OfType<BflMaterial>().ToList();
var messages = new Dictionary<BflStep, IReadOnlyList<BflConversationMessage>>();
if (includeConversations)
{
foreach (var step in BflStep.All)
{
if ((await conversations.GetAsync(new BflStepThreadLocation(projectId, step))).Thread is { } thread)
messages[step] = BflReflectionFolder.MessagesOf(thread);
}
}
var text = BflReflectionFolder.Build(new BflReflectionFolderInput(projectName, workStates, forms, materials, messages, includePersonalDisclosures, Tools.PluginSystem.I18N.I.Culture));
await this.StoreDraftAsync(location, text, BflStaleness.ConfirmedRevisionsOf(workStates));
}
catch (FileNotFoundException)
{
// The person deleted the preparation meanwhile; nothing is left to store.
}
catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or InvalidDataException)
{
logger.LogError(exception, "The BeyondFacts Lab could not put the reflection folder of '{ProjectId}' together.", projectId);
await messageBus.SendError(new(Icons.Material.Filled.SaveAs, TA("AI Studio could not create this material. Please try again.")));
}
finally
{
await this.NotifyAsync(location);
}
}
/// <summary>
/// Stops the model writing a result.
/// </summary>
/// <param name="location">The result.</param>
public Task CancelAsync(BflResultLocation location) => sessionService.CancelAsync(SessionKey(location));
/// <summary>
/// Stores the new draft of a result; a confirmed version stays as it is.
/// </summary>
/// <param name="location">The result.</param>
/// <param name="text">The text of the draft.</param>
/// <param name="workStateRevisions">The revisions of the confirmed work states the draft was built from.</param>
private async Task StoreDraftAsync(BflResultLocation location, string text, IReadOnlyDictionary<BflStep, int> workStateRevisions)
{
var result = await store.LoadResultAsync(location.ProjectId, location.Kind);
result.Draft = new BflResultVersion
{
Text = text,
WorkStateRevisions = new(workStateRevisions),
ChangedAtUtc = DateTimeOffset.UtcNow,
};
await store.SaveResultAsync(location.ProjectId, location.Kind, result);
}
/// <summary>
/// Tells every page which listens that a result changed.
/// </summary>
/// <param name="location">The result.</param>
private async Task NotifyAsync(BflResultLocation location)
{
if (this.ResultChanged is not { } handlers)
return;
foreach (var handler in handlers.GetInvocationList().Cast<Func<BflResultLocation, Task>>())
{
try
{
await handler(location);
}
catch (Exception exception)
{
// A page which went away meanwhile must not stop the work:
logger.LogDebug(exception, "A page of the BeyondFacts Lab could not show a change of a result.");
}
}
}
/// <summary>
/// Gets the key under which writing a result registers in AssistantSessionService, beside the conversations.
/// </summary>
/// <param name="location">The result.</param>
private static AssistantSessionKey SessionKey(BflResultLocation location) => new(Tools.Components.BEYOND_FACTS_LAB_ASSISTANT, location.Key);
}
@@ -0,0 +1,37 @@
namespace AIStudio.Assistants.BeyondFactsLab;
/// <summary>
/// The materials a person takes away from a preparation in the BeyondFacts Lab, in the last step.
/// </summary>
/// <remarks>
/// They are called results in the code, since BflMaterial already names what the person uploads. Each of them
/// is stored in a file of its own, see BflResultKindExtensions.FileName.
/// </remarks>
public enum BflResultKind
{
/// <summary>
/// All confirmed work states, the material, the open questions, and the revisions, put together word for word,
/// without a model.
/// </summary>
REFLECTION_FOLDER,
/// <summary>
/// One page on what the person stands for and why.
/// </summary>
POSITION_PAPER,
/// <summary>
/// The opening, the key messages, questions to others, and wordings for uncertainty or disagreement.
/// </summary>
CONVERSATION_GUIDE,
/// <summary>
/// Critical questions from the test situation with approaches to answering them.
/// </summary>
QUESTIONS_AND_ANSWERS,
/// <summary>
/// What the person still has to research, clarify, or decide before the event.
/// </summary>
OPEN_POINTS,
}
@@ -0,0 +1,68 @@
namespace AIStudio.Assistants.BeyondFactsLab;
public static class BflResultKindExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(BflResultKindExtensions).Namespace, nameof(BflResultKindExtensions));
private static string TA(string fallbackEN) => Tools.PluginSystem.I18N.I.TA(fallbackEN, typeof(BflResultKindExtensions).Namespace, nameof(BflResultKindExtensions));
/// <param name="kind">The kind of result.</param>
extension(BflResultKind kind)
{
/// <summary>
/// Gets the name of the result.
/// </summary>
public string Title => kind switch
{
BflResultKind.REFLECTION_FOLDER => TB("Reflection folder"),
BflResultKind.POSITION_PAPER => TB("Position paper"),
BflResultKind.CONVERSATION_GUIDE => TB("Conversation guide"),
BflResultKind.QUESTIONS_AND_ANSWERS => TB("Questions and answers"),
BflResultKind.OPEN_POINTS => TB("Open points and next steps"),
_ => string.Empty,
};
/// <summary>
/// Gets what the result contains, for the info symbol beside its name.
/// </summary>
public string Description => kind switch
{
BflResultKind.REFLECTION_FOLDER => TA("All your confirmed work states, your material, the open questions, and your revisions, word for word. If you like, with the complete conversations as an appendix."),
BflResultKind.POSITION_PAPER => TA("One page on what you stand for and why: your key statements, your reasons, the trade-offs between values, and the limits of your expertise."),
BflResultKind.CONVERSATION_GUIDE => TA("The opening, your key messages, questions to others, and wordings for uncertainty or disagreement. You can adapt it for a talk, a pitch, or a hearing."),
BflResultKind.QUESTIONS_AND_ANSWERS => TA("Critical questions from the test situation, your approaches to answering them, and the points on which you have no reliable answer."),
BflResultKind.OPEN_POINTS => TA("What you still have to research, clarify with others, or decide yourself before you appear."),
_ => string.Empty,
};
/// <summary>
/// Tells whether a model writes the result. The reflection folder is put together from what the person
/// confirmed, word for word.
/// </summary>
public bool IsWrittenByModel => kind is not BflResultKind.REFLECTION_FOLDER;
/// <summary>
/// Gets the name of the file in which a preparation keeps the result.
/// </summary>
/// <remarks>
/// These names are stored on disk, so they never change.
/// </remarks>
public string FileName => kind switch
{
BflResultKind.REFLECTION_FOLDER => "reflection-folder.json",
BflResultKind.POSITION_PAPER => "position-paper.json",
BflResultKind.CONVERSATION_GUIDE => "conversation-guide.json",
BflResultKind.QUESTIONS_AND_ANSWERS => "questions-and-answers.json",
BflResultKind.OPEN_POINTS => "open-points.json",
_ => throw new ArgumentOutOfRangeException(nameof(kind), kind, "The result has no file."),
};
/// <summary>
/// Gets every kind of result, in the order the last step shows them.
/// </summary>
public static IReadOnlyList<BflResultKind> All => Enum.GetValues<BflResultKind>();
}
}
@@ -0,0 +1,14 @@
namespace AIStudio.Assistants.BeyondFactsLab;
/// <summary>
/// Where a result belongs: to a preparation, as one of its kinds of results.
/// </summary>
/// <param name="ProjectId">The ID of the preparation.</param>
/// <param name="Kind">The kind of result.</param>
public sealed record BflResultLocation(Guid ProjectId, BflResultKind Kind)
{
/// <summary>
/// Gets a key which tells the result apart from every other one, e.g., for a running request.
/// </summary>
public string Key => $"{this.ProjectId:D}/results/{this.Kind.FileName}";
}
@@ -0,0 +1,37 @@
namespace AIStudio.Assistants.BeyondFactsLab;
/// <summary>
/// Where a result of a preparation stands, as the header of its panel shows it.
/// </summary>
public enum BflResultStatus
{
/// <summary>
/// This version of AI Studio cannot open the result.
/// </summary>
UNREADABLE,
/// <summary>
/// The result has neither a draft nor a confirmed version.
/// </summary>
NOT_CREATED,
/// <summary>
/// The model writes the result right now.
/// </summary>
WRITING,
/// <summary>
/// The result has a draft the person has not confirmed yet.
/// </summary>
DRAFT,
/// <summary>
/// The person confirmed the result, and it still fits the work states.
/// </summary>
CONFIRMED,
/// <summary>
/// The person confirmed the result, but a work state changed since.
/// </summary>
OUTDATED,
}
@@ -0,0 +1,34 @@
namespace AIStudio.Assistants.BeyondFactsLab;
/// <summary>
/// Reads the text of a result from the answer of the model.
/// </summary>
/// <remarks>
/// The request asks for plain Markdown, but some models wrap a document in a code block all the same. Such a block
/// would show the result as code and export it as code, so it is taken off; everything else stays as the model wrote
/// it, for the person to read and edit.
/// </remarks>
public static class BflResultText
{
/// <summary>
/// Reads the text of a result from the answer of the model.
/// </summary>
/// <param name="answer">The answer of the model.</param>
/// <returns>The text, without a code block around all of it; empty when the model wrote nothing.</returns>
public static string Read(string answer)
{
var text = answer.ReplaceLineEndings("\n").Trim();
if (!text.StartsWith("```", StringComparison.Ordinal) && !text.StartsWith("~~~", StringComparison.Ordinal))
return text;
var fence = text[..3];
var firstLineEnd = text.IndexOf('\n');
if (firstLineEnd < 0 || !text.EndsWith(fence, StringComparison.Ordinal) || text.Length - fence.Length <= firstLineEnd)
return text;
var inner = text[(firstLineEnd + 1)..^fence.Length];
// A fence inside means the block is one of several, not a wrapper around the whole answer:
return inner.Contains(fence, StringComparison.Ordinal) ? text : inner.Trim();
}
}
@@ -0,0 +1,26 @@
namespace AIStudio.Assistants.BeyondFactsLab;
/// <summary>
/// One version of a result: a draft, or the version the person confirmed.
/// </summary>
public sealed class BflResultVersion
{
/// <summary>
/// Gets or sets the text of the result, in Markdown.
/// </summary>
public string Text { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the revisions of the confirmed work states the result was built from, see
/// BflStaleness.ConfirmedRevisionsOf. A step without a confirmed work state at that time is missing.
/// </summary>
/// <remarks>
/// Editing the text keeps them: the person changes the wording, not what the result builds on.
/// </remarks>
public Dictionary<BflStep, int> WorkStateRevisions { get; set; } = [];
/// <summary>
/// Gets or sets when the lab wrote the draft, or when the person confirmed the result.
/// </summary>
public DateTimeOffset ChangedAtUtc { get; set; }
}
@@ -0,0 +1,159 @@
@inherits MSGComponentBase
<MudText Typo="Typo.h6" Class="mt-6 mb-1">@TA("What would you like to take away?")</MudText>
<MudText Typo="Typo.body2" Class="mb-3">@TA("The lab writes these materials from your confirmed work states. Check and edit each of them, and confirm it. Then you can export it as a document.")</MudText>
@if (this.MissingSteps.Count > 0)
{
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Dense="true" Class="mb-3">
@string.Format(Culture, TA("These steps have no confirmed work state yet: {0}. The materials use only what you confirmed and name what is still open."), string.Join(", ", this.MissingSteps.Select(step => $"„{step.Title}“")))
</MudAlert>
}
<MudButton Variant="@(this.AnyCreated ? Variant.Outlined : Variant.Filled)"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.AutoAwesome"
OnClick="@this.CreateAllAsync"
Disabled="@(!this.CanCreateAll)"
Class="mb-3">
@T("Create all materials in parallel")
</MudButton>
@* Only one material is open at a time, so that the list stays clear: *@
<MudExpansionPanels MultiExpansion="@false">
@foreach (var kind in BflResultKind.All)
{
var status = this.StatusOf(kind);
<MudExpansionPanel @key="kind" Class="border-solid border rounded-lg" Expanded="@(this.expandedKind == kind)" ExpandedChanged="@(expanded => this.SetExpanded(kind, expanded))">
<TitleContent>
<div class="d-flex align-center">
<MudIcon Icon="@StatusIcon(status)" Color="@StatusColor(status)" Class="mr-3"/>
<MudText Typo="Typo.h6">@kind.Title</MudText>
<MudTooltip Text="@kind.Description" Placement="Placement.Top">
<MudIcon Icon="@Icons.Material.Outlined.Info" Size="Size.Small" Color="Color.Info" Class="ml-2"/>
</MudTooltip>
<MudSpacer/>
<MudText Typo="Typo.caption" Class="mr-2">@this.StatusText(status)</MudText>
</div>
</TitleContent>
<ChildContent>
@if (!this.results.TryGetValue(kind, out var result))
{
<MudAlert Severity="Severity.Error" Variant="Variant.Outlined" Dense="true">
@TA("AI Studio cannot open this material. Its file may be damaged, or a newer version of AI Studio stored it. AI Studio leaves the file unchanged.")
</MudAlert>
}
else
{
@if (this.IsGenerating(kind))
{
<MudProgressLinear Color="Color.Primary" Indeterminate="true" Class="mb-1"/>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2" Class="mb-3">
<MudText Typo="Typo.caption">@T("The lab writes this material")</MudText>
<MudButton Size="Size.Small" StartIcon="@Icons.Material.Filled.Stop" OnClick="@(() => this.CancelAsync(kind))">@T("Stop")</MudButton>
</MudStack>
}
@if (result.Draft is { } draft)
{
<div class="border-dashed border rounded-lg pa-3 mb-3">
<MudText Typo="Typo.subtitle2" Class="mb-2">@T("Draft, not confirmed yet")</MudText>
@if (BflStaleness.IsOutdated(draft, this.WorkStates))
{
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Dense="true" Class="mb-2">
@TA("A work state changed since the lab wrote this draft. You can create it anew.")
</MudAlert>
}
@if (this.editing.Contains(kind))
{
<MudTextField T="string"
Value="@draft.Text"
ValueChanged="@(value => this.SetDraftAsync(kind, value))"
Label="@kind.Title"
Disabled="@this.IsBusy(kind)"
Variant="Variant.Outlined"
Lines="10"
Sizing="InputSizing.Auto"
MaxLines="30"/>
}
else
{
<div class="border rounded pa-2" style="max-height: 320px; overflow-y: auto;">
<MudMarkdown Value="@draft.Text" Props="Markdown.DefaultConfig" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE"/>
</div>
}
<MudStack Row="true" Spacing="1" Wrap="Wrap.Wrap" Class="mt-3">
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.CheckCircle" OnClick="@(() => this.ConfirmAsync(kind))" Disabled="@this.IsBusy(kind)">@T("Confirm")</MudButton>
@if (this.editing.Contains(kind))
{
<MudButton StartIcon="@Icons.Material.Filled.Preview" OnClick="@(() => this.ShowPreview(kind))" Disabled="@this.IsBusy(kind)">@T("Show preview")</MudButton>
}
else
{
<MudButton StartIcon="@Icons.Material.Filled.Edit" OnClick="@(() => this.StartEditing(kind))" Disabled="@this.IsBusy(kind)">@T("Edit")</MudButton>
}
<MudButton StartIcon="@Icons.Material.Filled.Delete" OnClick="@(() => this.DiscardDraftAsync(kind))" Disabled="@this.IsBusy(kind)">@T("Discard draft")</MudButton>
</MudStack>
</div>
}
else if (result.Confirmed is { } confirmed)
{
@if (BflStaleness.IsOutdated(confirmed, this.WorkStates))
{
<MudAlert Severity="Severity.Warning" Variant="Variant.Outlined" Dense="true" Class="mb-2">
@TA("A work state changed since you confirmed this material. Please create it anew, or check whether it still fits.")
</MudAlert>
}
else
{
<MudText Typo="Typo.caption" Class="mb-2 d-block">@string.Format(Culture, TA("You confirmed this material on {0}."), confirmed.ChangedAtUtc.ToLocalTime().ToString("g", Culture))</MudText>
}
<div class="border rounded pa-2 mb-3" style="max-height: 320px; overflow-y: auto;">
<MudMarkdown Value="@confirmed.Text" Props="Markdown.DefaultConfig" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE"/>
</div>
<MudStack Row="true" Spacing="1" Wrap="Wrap.Wrap" Class="mb-3">
<MudMenu Label="@T("Export")"
StartIcon="@Icons.Material.Filled.Save"
EndIcon="@Icons.Material.Filled.KeyboardArrowDown"
Variant="Variant.Filled"
Color="Color.Primary"
MaxHeight="@MenuDefaults.MAX_HEIGHT"
Disabled="@this.IsBusy(kind)">
@foreach (var format in FileExportFormat.DocumentFormats)
{
<MudMenuItem @key="format" OnClick="@(() => this.ExportAsync(kind, confirmed, format))" Icon="@format.Icon" Label="@format.Name"/>
}
<MudDivider/>
@foreach (var format in FileExportFormat.TextFormats)
{
<MudMenuItem @key="format" OnClick="@(() => this.ExportAsync(kind, confirmed, format))" Icon="@format.Icon" Label="@format.Name"/>
}
</MudMenu>
<MudButton StartIcon="@Icons.Material.Filled.Edit" OnClick="@(() => this.EditAsync(kind))" Disabled="@this.IsBusy(kind)">@T("Edit")</MudButton>
</MudStack>
}
@if (kind is BflResultKind.REFLECTION_FOLDER)
{
<MudStack Row="true" Spacing="3" Wrap="Wrap.Wrap" Class="mb-1">
<MudSwitch T="bool" @bind-Value="@this.includePersonalDisclosures" Color="Color.Primary" Disabled="@this.IsBusy(kind)">@TA("Include personal disclosures")</MudSwitch>
<MudSwitch T="bool" @bind-Value="@this.includeConversations" Color="Color.Primary" Disabled="@this.IsBusy(kind)">@TA("Add the conversations as an appendix")</MudSwitch>
</MudStack>
}
<MudButton Variant="@(result.Draft is null && result.Confirmed is null ? Variant.Filled : Variant.Outlined)"
Color="Color.Primary"
StartIcon="@(kind.IsWrittenByModel ? Icons.Material.Filled.AutoAwesome : Icons.Material.Filled.FolderCopy)"
OnClick="@(() => this.CreateAsync(kind))"
Disabled="@(this.IsBusy(kind) || kind.IsWrittenByModel && this.ProviderIssue is not null)">
@(result.Draft is null && result.Confirmed is null ? T("Create") : T("Create anew"))
</MudButton>
}
</ChildContent>
</MudExpansionPanel>
}
</MudExpansionPanels>
@@ -0,0 +1,413 @@
using System.Globalization;
using AIStudio.Chat;
using AIStudio.Components;
using AIStudio.Dialogs;
using AIStudio.Tools.Services;
using Microsoft.AspNetCore.Components;
using DialogOptions = AIStudio.Dialogs.DialogOptions;
namespace AIStudio.Assistants.BeyondFactsLab;
/// <summary>
/// The results of a preparation in the last step of the BeyondFacts Lab: what the person takes away, each with its
/// draft, its confirmed version, and its export.
/// </summary>
/// <remarks>
/// The component loads and stores the results itself; the page keeps the work states, which tell whether a result is
/// outdated. The model writes in BflResultGenerator, so that the work goes on while the person looks elsewhere; the
/// component reads the results again whenever the generator says one changed. Only a confirmed result can be exported.
/// </remarks>
public partial class BflResults : MSGComponentBase
{
[Inject]
private BeyondFactsLabStore Store { get; init; } = null!;
[Inject]
private BflResultGenerator Generator { get; init; } = null!;
[Inject]
private RustService RustService { get; init; } = null!;
[Inject]
private PandocAvailabilityService PandocAvailability { get; init; } = null!;
[Inject]
private AIGeneratedContentDisclosureService DisclosureService { get; init; } = null!;
[Inject]
private IDialogService DialogService { get; init; } = null!;
[Inject]
private ILogger<BflResults> Logger { get; init; } = null!;
/// <summary>
/// Gets or sets the ID of the preparation whose results the component shows.
/// </summary>
[Parameter, EditorRequired]
public Guid ProjectId { get; set; }
/// <summary>
/// Gets or sets the name of the preparation, for the reflection folder and the names of exported files.
/// </summary>
[Parameter, EditorRequired]
public string ProjectName { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the work states of the preparation, by their steps.
/// </summary>
[Parameter, EditorRequired]
public IReadOnlyDictionary<BflStep, BflWorkState> WorkStates { get; set; } = new Dictionary<BflStep, BflWorkState>();
/// <summary>
/// Gets or sets the forms of the preparation, by their steps, which the reflection folder needs to tell where a
/// work state stands.
/// </summary>
[Parameter, EditorRequired]
public IReadOnlyDictionary<BflStep, BflStepFormData> Forms { get; set; } = new Dictionary<BflStep, BflStepFormData>();
/// <summary>
/// Gets or sets the callback raised after a result was stored, with the preparation and its new time of change.
/// </summary>
[Parameter]
public EventCallback<BflProject> ResultStored { get; set; }
/// <summary>
/// Gets or sets the provider which writes the results.
/// </summary>
[Parameter, EditorRequired]
public AIStudio.Settings.Provider Provider { get; set; } = Settings.Provider.NONE;
/// <summary>
/// Gets or sets why the provider cannot write, or null when it can.
/// </summary>
[Parameter]
public string? ProviderIssue { get; set; }
private static CultureInfo Culture => Tools.PluginSystem.I18N.I.Culture;
/// <summary>
/// The results this version can open, by their kinds.
/// </summary>
private Dictionary<BflResultKind, BflResult> results = [];
/// <summary>
/// The preparation whose results were loaded, to load again when the page shows another one.
/// </summary>
private Guid loadedProjectId;
/// <summary>
/// The result whose panel is open, or null while all are closed. Only one is open at a time.
/// </summary>
private BflResultKind? expandedKind = BflResultKind.All[0];
/// <summary>
/// The results whose draft the person edits as text instead of reading its preview.
/// </summary>
private readonly HashSet<BflResultKind> editing = [];
/// <summary>
/// The results the component stores or puts together right now.
/// </summary>
private readonly HashSet<BflResultKind> saving = [];
/// <summary>
/// Whether the reflection folder takes up personal disclosures.
/// </summary>
private bool includePersonalDisclosures;
/// <summary>
/// Whether the reflection folder takes up the conversations of the steps as an appendix.
/// </summary>
private bool includeConversations;
/// <summary>
/// Gets the steps without a confirmed work state, in their order.
/// </summary>
private IReadOnlyList<BflStep> MissingSteps => [.. BflStep.All.Where(step => this.WorkStates.GetValueOrDefault(step)?.Confirmed is null)];
/// <inheritdoc />
protected override async Task OnInitializedAsync()
{
this.Generator.ResultChanged += this.OnResultChangedAsync;
await base.OnInitializedAsync();
}
/// <inheritdoc />
protected override async Task OnParametersSetAsync()
{
await base.OnParametersSetAsync();
if (this.loadedProjectId == this.ProjectId)
return;
this.loadedProjectId = this.ProjectId;
this.editing.Clear();
this.results = [];
await this.LoadAsync();
}
/// <inheritdoc />
protected override void DisposeResources()
{
this.Generator.ResultChanged -= this.OnResultChangedAsync;
base.DisposeResources();
}
private bool IsGenerating(BflResultKind kind) => this.Generator.IsRunning(new BflResultLocation(this.ProjectId, kind));
private bool IsBusy(BflResultKind kind) => this.saving.Contains(kind) || this.IsGenerating(kind);
/// <summary>
/// Gets the results which "Create all materials in parallel" creates: every one which can be opened and is idle.
/// </summary>
private IReadOnlyList<BflResultKind> CreatableKinds => [.. BflResultKind.All.Where(kind => this.results.ContainsKey(kind) && !this.IsBusy(kind))];
private bool CanCreateAll => this.ProviderIssue is null && this.CreatableKinds.Count > 0;
private bool AnyCreated => this.results.Values.Any(result => result.Draft is not null || result.Confirmed is not null);
/// <summary>
/// Tells where a result stands, for the header of its panel.
/// </summary>
/// <param name="kind">The kind of result.</param>
private BflResultStatus StatusOf(BflResultKind kind)
{
if (this.IsGenerating(kind))
return BflResultStatus.WRITING;
return this.results.GetValueOrDefault(kind) switch
{
null => BflResultStatus.UNREADABLE,
{ Draft: not null } => BflResultStatus.DRAFT,
{ Confirmed: { } confirmed } => BflStaleness.IsOutdated(confirmed, this.WorkStates) ? BflResultStatus.OUTDATED : BflResultStatus.CONFIRMED,
_ => BflResultStatus.NOT_CREATED
};
}
private static string StatusIcon(BflResultStatus status) => status switch
{
BflResultStatus.UNREADABLE => Icons.Material.Filled.Error,
BflResultStatus.WRITING => Icons.Material.Filled.HourglassTop,
BflResultStatus.DRAFT => Icons.Material.Filled.EditNote,
BflResultStatus.CONFIRMED => Icons.Material.Filled.CheckCircle,
BflResultStatus.OUTDATED => Icons.Material.Filled.Update,
_ => Icons.Material.Filled.RadioButtonUnchecked
};
private static Color StatusColor(BflResultStatus status) => status switch
{
BflResultStatus.UNREADABLE => Color.Error,
BflResultStatus.WRITING => Color.Primary,
BflResultStatus.DRAFT => Color.Info,
BflResultStatus.CONFIRMED => Color.Success,
BflResultStatus.OUTDATED => Color.Warning,
_ => Color.Default
};
private string StatusText(BflResultStatus status) => status switch
{
BflResultStatus.UNREADABLE => T("Cannot be opened"),
BflResultStatus.WRITING => T("Being written"),
BflResultStatus.DRAFT => T("Draft"),
BflResultStatus.CONFIRMED => T("Confirmed"),
BflResultStatus.OUTDATED => T("Outdated"),
_ => T("Not created yet")
};
/// <summary>
/// Opens the panel of a result and closes the others, or closes it.
/// </summary>
/// <param name="kind">The kind of result.</param>
/// <param name="expanded">Whether the panel is open now.</param>
private void SetExpanded(BflResultKind kind, bool expanded)
{
if (expanded)
this.expandedKind = kind;
else if (this.expandedKind == kind)
this.expandedKind = null;
}
/// <summary>
/// Reads the results of the preparation again once the generator started, ended, or stored a draft.
/// </summary>
/// <param name="location">The result which changed.</param>
private Task OnResultChangedAsync(BflResultLocation location)
{
if (location.ProjectId != this.ProjectId)
return Task.CompletedTask;
return this.InvokeAsync(async () =>
{
await this.LoadAsync();
this.StateHasChanged();
});
}
/// <summary>
/// Reads the results of the preparation shown.
/// </summary>
private async Task LoadAsync()
{
var projectId = this.ProjectId;
var loaded = await this.Store.LoadResultsAsync(projectId);
// The page may have shown another preparation meanwhile:
if (projectId == this.ProjectId)
this.results = new(loaded);
}
/// <summary>
/// Lets the model write a result, or puts the reflection folder together.
/// </summary>
/// <param name="kind">The kind of result.</param>
private async Task CreateAsync(BflResultKind kind)
{
this.editing.Remove(kind);
if (kind.IsWrittenByModel)
{
if (this.ProviderIssue is null)
await this.Generator.GenerateAsync(new BflResultLocation(this.ProjectId, kind), this.Provider);
return;
}
this.saving.Add(kind);
try
{
await this.Generator.AssembleReflectionFolderAsync(this.ProjectId, this.ProjectName, this.Forms, this.includePersonalDisclosures, this.includeConversations);
}
finally
{
this.saving.Remove(kind);
}
}
/// <summary>
/// Creates every idle result at once: the model writes the four of them in parallel, while AI Studio puts the
/// reflection folder together with the choices of its panel.
/// </summary>
/// <remarks>
/// Like "Create anew", a new draft replaces an earlier one, while a confirmed version stays until the person
/// confirms the new draft. Since a draft may hold edits of the person, the component asks first when there is one.
/// </remarks>
private async Task CreateAllAsync()
{
var kinds = this.CreatableKinds;
if (this.ProviderIssue is not null || kinds.Count is 0)
return;
if (kinds.Any(kind => this.results[kind].Draft is not null))
{
var parameters = new DialogParameters<ConfirmDialog>
{
{ dialog => dialog.Message, TA("Replace the drafts you have not confirmed yet? Materials you confirmed stay until you confirm their new drafts.") }
};
var reference = await this.DialogService.ShowAsync<ConfirmDialog>(T("Create all materials in parallel"), parameters, DialogOptions.FULLSCREEN);
var answer = await reference.Result;
if (answer is null || answer.Canceled)
return;
}
await Task.WhenAll(kinds.Select(this.CreateAsync));
}
private Task CancelAsync(BflResultKind kind) => this.Generator.CancelAsync(new BflResultLocation(this.ProjectId, kind));
private void StartEditing(BflResultKind kind) => this.editing.Add(kind);
private void ShowPreview(BflResultKind kind) => this.editing.Remove(kind);
private async Task SetDraftAsync(BflResultKind kind, string? text)
{
if (this.results.GetValueOrDefault(kind) is not { Draft: { } draft } result)
return;
draft.Text = text ?? string.Empty;
await this.SaveAsync(kind, result);
}
private async Task ConfirmAsync(BflResultKind kind)
{
if (this.results.GetValueOrDefault(kind) is not { Draft: { } draft } result)
return;
result.Confirm(draft.Text, DateTimeOffset.UtcNow);
this.editing.Remove(kind);
await this.SaveAsync(kind, result);
}
private async Task DiscardDraftAsync(BflResultKind kind)
{
if (this.results.GetValueOrDefault(kind) is not { Draft: not null } result)
return;
result.Draft = null;
this.editing.Remove(kind);
await this.SaveAsync(kind, result);
}
private async Task EditAsync(BflResultKind kind)
{
if (this.results.GetValueOrDefault(kind) is not { Confirmed: not null } result)
return;
result.Edit();
this.editing.Add(kind);
await this.SaveAsync(kind, result);
}
/// <summary>
/// Exports the confirmed version of a result, with the notice that AI generated it when the person or the
/// organization switched that on.
/// </summary>
/// <remarks>
/// The format knows who writes it, as in the chat: Pandoc writes documents and HTML, AI Studio itself writes
/// Markdown.
/// </remarks>
/// <param name="kind">The kind of result.</param>
/// <param name="confirmed">The confirmed version.</param>
/// <param name="format">The format of the file.</param>
private async Task ExportAsync(BflResultKind kind, BflResultVersion confirmed, FileExportFormat format)
{
var fileName = $"{this.ProjectName} - {kind.Title}";
this.saving.Add(kind);
try
{
if (format.UsesPandoc)
await PandocExport.ToDocument(this.RustService, this.PandocAvailability, this.DisclosureService, kind.Title, format, new ContentText { Text = confirmed.Text }, fileName);
else
await PlainFileExport.ToFile(this.RustService, kind.Title, format, this.DisclosureService.AddDisclosureToMarkdown(confirmed.Text), fileName);
}
catch (ArgumentOutOfRangeException exception)
{
this.Logger.LogError(exception, "Could not export a result of the BeyondFacts Lab, because no exporter writes the format {ExportFormat}.", format);
await this.MessageBus.SendError(new(Icons.Material.Filled.Error, TA("AI Studio could not export this material. Please try another format.")));
}
finally
{
this.saving.Remove(kind);
}
}
private async Task SaveAsync(BflResultKind kind, BflResult result)
{
this.saving.Add(kind);
try
{
var project = await this.Store.SaveResultAsync(this.ProjectId, kind, result);
await this.ResultStored.InvokeAsync(project);
}
catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or InvalidDataException)
{
this.Logger.LogError(exception, "Could not save the result '{Kind}' of a preparation in the BeyondFacts Lab.", kind);
await this.MessageBus.SendError(new(Icons.Material.Filled.SaveAs, TA("AI Studio could not save this material. Please try again.")));
}
finally
{
this.saving.Remove(kind);
}
}
}
@@ -4,13 +4,13 @@ using System.Text;
namespace AIStudio.Assistants.BeyondFactsLab;
/// <summary>
/// Tells whether a confirmed work state of the BeyondFacts Lab still fits what it builds on.
/// Tells whether a confirmed work state or a result of the BeyondFacts Lab still fits what it builds on.
/// </summary>
/// <remarks>
/// The answer is computed whenever it is needed and never stored, so that it cannot drift from the work states. A
/// confirmed work state remembers the revisions of the earlier steps and a fingerprint of the form of its step;
/// comparing both with the present ones gives the answer. A changed form weighs less than a changed earlier step:
/// the person may have only corrected a typo.
/// the person may have only corrected a typo. A result remembers the revisions of the work states of all steps.
/// </remarks>
public static class BflStaleness
{
@@ -60,6 +60,36 @@ public static class BflStaleness
return revisions;
}
/// <summary>
/// Gets the revisions of the confirmed work states of all steps, which a result remembers when the lab writes it.
/// </summary>
/// <param name="workStates">The work states of the preparation, by their steps.</param>
/// <returns>The revision of each step with a confirmed work state.</returns>
public static IReadOnlyDictionary<BflStep, int> ConfirmedRevisionsOf(IReadOnlyDictionary<BflStep, BflWorkState> workStates)
{
var revisions = new Dictionary<BflStep, int>();
foreach (var step in BflStep.All)
{
if (workStates.GetValueOrDefault(step)?.Confirmed is { } confirmed)
revisions[step] = confirmed.Revision;
}
return revisions;
}
/// <summary>
/// Tells whether a version of a result no longer fits the work states: a step was confirmed for the first time,
/// confirmed anew, or withdrawn since the lab wrote it.
/// </summary>
/// <param name="version">The version of the result.</param>
/// <param name="workStates">The work states of the preparation, by their steps.</param>
/// <returns>True, when the result is outdated.</returns>
public static bool IsOutdated(BflResultVersion version, IReadOnlyDictionary<BflStep, BflWorkState> workStates)
{
var revisions = ConfirmedRevisionsOf(workStates);
return revisions.Count != version.WorkStateRevisions.Count || revisions.Any(revision => version.WorkStateRevisions.GetValueOrDefault(revision.Key) != revision.Value);
}
/// <summary>
/// Computes the fingerprint of a form, which tells whether the person changed it.
/// </summary>
@@ -1,4 +1,3 @@
using AIStudio.Chat;
using AIStudio.Provider;
using AIStudio.Tools.AssistantSessions;
@@ -93,11 +92,11 @@ public sealed class BflWorkStateGenerator(BeyondFactsLabStore store, BflConversa
sessionId = (await sessionService.TryBeginAsync(sessionKey, Tools.Components.BEYOND_FACTS_LAB_ASSISTANT.Name, cancellation, null, new(StringComparer.Ordinal))).SessionId;
await this.NotifyAsync(location);
var answer = BflMarkdownSections.Read(await AskAsync(hidden, provider, request, requestMaterial.Images, cancellation.Token), location.Step, form);
var answer = BflMarkdownSections.Read(await BflHiddenRequest.AskAsync(hidden, provider, request, requestMaterial.Images, cancellation.Token), location.Step, form);
if (answer.Problems.Count > 0 && !cancellation.IsCancellationRequested)
{
logger.LogInformation("The model wrote a work state of the BeyondFacts Lab with {Count} problems; it may correct them once.", answer.Problems.Count);
answer = BflMarkdownSections.Read(await AskAsync(hidden, provider, BflPromptComposer.ComposeWorkStateRepairRequest(answer.Problems), requestMaterial.Images, cancellation.Token), location.Step, form);
answer = BflMarkdownSections.Read(await BflHiddenRequest.AskAsync(hidden, provider, BflPromptComposer.ComposeWorkStateRepairRequest(answer.Problems), requestMaterial.Images, cancellation.Token), location.Step, form);
}
if (cancellation.IsCancellationRequested)
@@ -164,41 +163,6 @@ public sealed class BflWorkStateGenerator(BeyondFactsLabStore store, BflConversa
/// <param name="location">The step.</param>
public Task CancelAsync(BflStepThreadLocation location) => sessionService.CancelAsync(SessionKey(location));
/// <summary>
/// Sends a request in the hidden copy of a conversation and waits for the whole answer.
/// </summary>
/// <param name="hidden">The hidden copy of the conversation, which keeps the request and the answer.</param>
/// <param name="provider">The provider which answers.</param>
/// <param name="text">The request.</param>
/// <param name="images">The images of the material, which go along with the first message.</param>
/// <param name="token">The cancellation token.</param>
/// <returns>The answer, empty when the provider failed.</returns>
private static async Task<string> AskAsync(ChatThread hidden, AIStudio.Settings.Provider provider, string text, IReadOnlyList<FileAttachmentImage> images, CancellationToken token)
{
var request = new ContentText { Text = text };
hidden.Blocks.Add(new ContentBlock
{
Time = DateTimeOffset.Now,
ContentType = ContentType.TEXT,
Role = ChatRole.USER,
Content = request,
HideFromUser = true
});
var answer = new ContentText { InitialRemoteWait = true };
hidden.Blocks.Add(new ContentBlock
{
Time = DateTimeOffset.Now,
ContentType = ContentType.TEXT,
Role = ChatRole.AI,
Content = answer,
HideFromUser = true
});
await answer.CreateFromProviderAsync(provider.CreateProvider(), provider.Model, request, BflConversationService.WithImages(hidden, images), token);
return answer.Text;
}
/// <summary>
/// Tells every page which listens that a work state changed.
/// </summary>
@@ -41,6 +41,7 @@ Für schnelle Texte wie eine Pressemitteilung passen der Chat von AI Studio oder
- Im Bereich „Material“ neben den Schritten kann die Person Dokumente hinzufügen, etwa Notizen, einen Vortragstext, ein Paper oder die Einladung, außerdem Audio- und Videoaufnahmen, etwa ein Interview, und Bilder, etwa ein Poster. Aufnahmen lässt das Lab vom Transkriptionsanbieter von AI Studio verschriftlichen; Bilder sieht nur ein Modell, das Bilder verarbeiten kann. Das Material gilt für alle Schritte: Das Lab liest es in jedem Gespräch mit und fragt danach. Reicht der Kontext des Modells nicht für alles, liest es nur den Anfang eines Materials und zeigt das an.
- Mit „Gespräch beginnen“ eröffnet das Lab das Gespräch eines Schritts. Die Person kann auch selbst zuerst schreiben und sagen, wobei sie Unterstützung möchte, etwa bei ihrer Rolle, ihrer Strategie oder einer kritischen Fragerunde.
- Unter dem Gespräch eines Schritts erzeugt das Lab auf Wunsch einen Arbeitsstand: eine Zusammenfassung dessen, was die Person in dem Schritt geklärt hat. Sie prüft, bearbeitet und bestätigt ihn; die späteren Schritte bauen auf den bestätigten Arbeitsständen auf. Dabei schlägt das Lab Werte für leere Felder in „Ihre Angaben“ vor, die die Person einzeln übernimmt.
- Im letzten Schritt erstellt das Lab aus den bestätigten Arbeitsständen fünf Materialien: eine Reflexionsmappe, ein Positionsblatt, einen Gesprächsleitfaden, Fragen und Antwortansätze sowie offene Punkte und nächste Schritte. Die Person prüft, bearbeitet und bestätigt jedes davon und exportiert es als Dokument. Persönliche Angaben nimmt die Reflexionsmappe nur auf, wenn die Person es wählt.
- Die Schritte bauen aufeinander auf, die Person kann sie aber in beliebiger Reihenfolge bearbeiten.
- Eine Vorbereitung dauert etwa 30 bis 60 Minuten. Die Person kann jederzeit unterbrechen: AI Studio speichert ihre Angaben und Gespräche, und sie macht später dort weiter.
- Für jede Vorbereitung wählt die Person einen KI-Anbieter. Das Lab bietet nur Anbieter an, denen sie oder ihre Organisation genug vertraut, und das Modell muss mindestens 32.000 Token auf einmal lesen können.
@@ -0,0 +1,23 @@
Schreibe jetzt den Gesprächsleitfaden der Person: was sie bei ihrem Auftritt sagen und fragen kann, in Formulierungen, die sie so aussprechen kann. Die Person prüft und bearbeitet ihn, bevor sie ihn bestätigt und exportiert.
# Grundlage
- Stütze dich auf die bestätigten Arbeitsstände, die Angaben der Person, ihr Material und dieses Gespräch. Erfinde keine Positionen, Argumente, Belege, Zahlen oder Quellen dazu.
- Richte den Leitfaden nach dem Format der Veranstaltung, ihrem Publikum und der Redezeit aus den Angaben, etwa für einen Vortrag, einen Pitch, eine Anhörung oder ein Podium. Fehlen diese Angaben, schreibe ihn für ein Podium und sage das in einem Satz unter der Überschrift.
- Persönliche Angaben, etwa wie das Thema die Person persönlich berührt, gehören nicht hinein, solange die Person sie nicht selbst als Teil ihres Auftritts bestätigt hat.
- Für diese Schritte gibt es noch keinen bestätigten Arbeitsstand: {{MISSING_WORK_STATES}} Fülle ihre Themen nicht mit Vermutungen. Fehlt dadurch ein Teil des Leitfadens, schreibe dort kurz, dass er noch offen ist.
# Inhalt
1. Einstieg: zwei bis drei Sätze, mit denen die Person beginnt.
2. Zentrale Botschaften: drei, jede in einem Satz, dazu ein Beispiel oder Beleg und ein Übergang zur nächsten.
3. Fragen an andere: Fragen an andere Teilnehmende oder an das Publikum, die das Gespräch voranbringen.
4. Formulierungen für Unsicherheit: wie die Person sagt, was unsicher oder unbekannt ist, ohne Vertrauen in die Wissenschaft zu untergraben.
5. Formulierungen für Meinungsverschiedenheiten: wie die Person widerspricht oder eine Wertabwägung offenlegt, sachlich und respektvoll.
6. Abschluss: ein bis zwei Sätze, mit denen die Person endet.
# Form
- Beginne mit einer Überschrift erster Ebene, die den Leitfaden benennt, und gliedere die Teile mit Überschriften zweiter Ebene.
- Schreibe die Formulierungen in der ersten Person, so wie die Person sie sagen würde, ohne Anrede an die Person und in der Sprache des Gesprächs.
- Antworte nur mit dem Leitfaden in Markdown, ohne Einleitung und ohne Nachsatz, und setze ihn nicht in einen Codeblock.
@@ -0,0 +1,21 @@
Schreibe jetzt die offenen Punkte und nächsten Schritte der Person: was sie vor ihrem Auftritt noch recherchieren, mit anderen klären oder selbst entscheiden muss. Die Person prüft und bearbeitet die Liste, bevor sie sie bestätigt und exportiert.
# Grundlage
- Sammle die offenen Punkte aus allen bestätigten Arbeitsständen, dazu, was die Person im letzten Schritt offen gelassen oder als nächsten Schritt genannt hat, und was in diesem Gespräch offen geblieben ist. Führe gleiche Punkte zusammen. Erfinde keine Aufgaben dazu.
- Für diese Schritte gibt es noch keinen bestätigten Arbeitsstand: {{MISSING_WORK_STATES}} Nimm jeden von ihnen als eigenen Punkt auf: Die Person sollte ihn noch durcharbeiten oder seinen Arbeitsstand bestätigen.
- Persönliche Angaben, etwa wie das Thema die Person persönlich berührt, gehören nicht hinein.
# Inhalt
1. Recherchieren: was die Person noch nachlesen, prüfen oder belegen muss.
2. Mit anderen klären: was sie mit wem klären muss, etwa mit den Veranstaltenden, der Pressestelle oder Kolleginnen und Kollegen. Nenne die Ansprechpersonen nur, wenn die Person sie genannt hat.
3. Selbst entscheiden: was die Person für sich entscheiden muss, etwa eine Wertabwägung oder ihre Rolle.
Ordne die Punkte in jedem Teil danach, was vor dem Auftritt am dringendsten ist. Bleibt ein Teil leer, schreibe das in einem Satz.
# Form
- Beginne mit einer Überschrift erster Ebene, die die Liste benennt, und gliedere die drei Teile mit Überschriften zweiter Ebene.
- Schreibe jeden Punkt als Aufgabe zum Abhaken, also als Zeile mit „- [ ] “, knapp, ohne Anrede an die Person und in der Sprache des Gesprächs.
- Antworte nur mit der Liste in Markdown, ohne Einleitung und ohne Nachsatz, und setze sie nicht in einen Codeblock.
@@ -0,0 +1,23 @@
Schreibe jetzt das Positionsblatt der Person: eine Seite, die sie vor ihrem Auftritt liest und auf die sie währenddessen schauen kann. Es hält fest, was sie vertritt und warum. Die Person prüft und bearbeitet es, bevor sie es bestätigt und exportiert.
# Grundlage
- Stütze dich auf die bestätigten Arbeitsstände, die Angaben der Person, ihr Material und dieses Gespräch. Erfinde keine Positionen, Argumente, Belege, Zahlen oder Quellen dazu.
- Übernimm Deutungen, Werte oder Motive nur, wenn die Person sie selbst bestätigt hat.
- Persönliche Angaben, etwa wie das Thema die Person persönlich berührt, gehören nicht hinein: Die Person kann das Blatt weitergeben.
- Für diese Schritte gibt es noch keinen bestätigten Arbeitsstand: {{MISSING_WORK_STATES}} Fülle ihre Themen nicht mit Vermutungen. Fehlt dadurch ein Teil des Blatts, schreibe dort kurz, dass er noch offen ist.
# Inhalt
1. Kernposition: ein bis zwei Sätze, was die Person vertritt.
2. Zentrale Aussagen: drei bis fünf, jede mit ihrer Begründung und, wo vorhanden, dem Beleg oder dem Material, auf das sie sich stützt.
3. Wertabwägungen: welche Werte die Position tragen und wo die Person zwischen ihnen abwägt.
4. Grenzen der eigenen Expertise: was die Person nicht beurteilen kann, was unsicher ist und was sie bewusst offen lässt.
5. Rolle: in welcher Rolle die Person spricht und was sie mit ihrem Beitrag erreichen möchte.
# Form
- Höchstens etwa 400 Wörter, damit das Blatt auf eine Seite passt.
- Beginne mit einer Überschrift erster Ebene, die das Blatt als Positionsblatt benennt, und gliedere die Teile mit Überschriften zweiter Ebene.
- Schreibe aus der Sicht der Person in der ersten Person, knapp, in Stichpunkten oder kurzen Sätzen, ohne Anrede an die Person und in der Sprache des Gesprächs.
- Antworte nur mit dem Positionsblatt in Markdown, ohne Einleitung und ohne Nachsatz, und setze es nicht in einen Codeblock.
@@ -0,0 +1,19 @@
Schreibe jetzt die Fragen und Antwortansätze der Person: die kritischen Nachfragen, die ihr bei ihrem Auftritt begegnen können, und wie sie darauf antworten kann. Die Person prüft und bearbeitet sie, bevor sie sie bestätigt und exportiert.
# Grundlage
- Die Fragen kommen vor allem aus der Erprobung in der Testsituation. Hat die Testsituation keinen bestätigten Arbeitsstand, leite wahrscheinliche Fragen aus den übrigen Arbeitsständen ab und schreibe unter die Überschrift, dass diese Fragen noch nicht erprobt sind.
- Die Antwortansätze stützen sich auf die bestätigten Arbeitsstände, die Angaben der Person, ihr Material und dieses Gespräch. Erfinde keine Positionen, Argumente, Belege, Zahlen oder Quellen dazu.
- Persönliche Angaben, etwa wie das Thema die Person persönlich berührt, gehören nicht hinein, solange die Person sie nicht selbst als Teil ihrer Antwort bestätigt hat.
- Für diese Schritte gibt es noch keinen bestätigten Arbeitsstand: {{MISSING_WORK_STATES}} Fülle ihre Themen nicht mit Vermutungen.
# Inhalt
1. Kritische Fragen mit Antwortansatz: fünf bis acht Fragen. Zu jeder: die Frage so, wie sie gestellt werden könnte; die Kernantwort in ein bis zwei Sätzen; worauf die Antwort sich stützt und was an ihr unsicher ist; wo die Person ihre Grenze zieht.
2. Ohne belastbare Antwort: die Punkte, bei denen die Person ausdrücklich keine belastbare Antwort hat, jeweils mit einer ehrlichen Formulierung dafür. Gibt es keine, schreibe das in einem Satz.
# Form
- Beginne mit einer Überschrift erster Ebene, die das Material benennt, gliedere die beiden Teile mit Überschriften zweiter Ebene und jede Frage mit einer Überschrift dritter Ebene.
- Schreibe die Antwortansätze in der ersten Person, so wie die Person sie sagen würde, ohne Anrede an die Person und in der Sprache des Gesprächs.
- Antworte nur mit den Fragen und Antwortansätzen in Markdown, ohne Einleitung und ohne Nachsatz, und setze sie nicht in einen Codeblock.
@@ -4,18 +4,20 @@ In diesem Schritt hältst du mit der Person fest, was sie aus ihrer Vorbereitung
### Deine erste Nachricht
Stelle die Leitfrage dieses Schritts: „Was haben Sie gegenüber Ihrer Ausgangsposition verändert, beibehalten oder offengelassen, und weshalb?“ Hat die Person sie in den Angaben schon beantwortet, greife ihre Antwort auf und frage nach, wo es sich lohnt. Nenne danach kurz die Materialien, die du erstellen kannst.
Stelle die Leitfrage dieses Schritts: „Was haben Sie gegenüber Ihrer Ausgangsposition verändert, beibehalten oder offengelassen, und weshalb?“ Hat die Person sie in den Angaben schon beantwortet, greife ihre Antwort auf und frage nach, wo es sich lohnt. Nenne danach kurz die Materialien, die das Lab unter diesem Gespräch für sie erstellt.
### Materialien
Erstelle sie nur auf Wunsch, eines nach dem anderen, mit dem, was die Angaben, das Material der Person und das Gespräch enthalten. Benenne, was dafür noch fehlt, statt es zu erfinden.
Unter diesem Gespräch erstellt das Lab fünf Materialien. Die Person prüft, bearbeitet und bestätigt jedes davon und exportiert es als Dokument:
- Reflexionsmappe: die Ergebnisse aller Schritte, Quellen, darunter das Material der Person, offene Fragen und Überarbeitungen.
- Reflexionsmappe: die bestätigten Arbeitsstände aller Schritte, das Material der Person, offene Fragen und Überarbeitungen. AI Studio setzt sie wörtlich zusammen, ohne Modell.
- Positionsblatt, höchstens eine Seite: Was vertrete ich und warum? Zentrale Aussagen, Begründungen, Wertabwägungen und die Grenzen der eigenen Expertise.
- Gesprächsleitfaden: Einstieg, zentrale Botschaften, Fragen an andere und Formulierungen für Unsicherheit oder Meinungsverschiedenheiten; anpassbar für Vortrag, Pitch oder Anhörung.
- Fragen und Antwortansätze: kritische Nachfragen, eigene Antwortansätze und Punkte, auf die die Person ausdrücklich keine belastbare Antwort hat.
- Offene Punkte und nächste Schritte: Was muss die Person vor dem Auftritt recherchieren, mit anderen klären oder selbst entscheiden?
Diese Materialien schreibst du nicht im Gespräch. Fragt die Person danach, verweise sie auf den Bereich unter dem Gespräch. Die Materialien bauen auf den bestätigten Arbeitsständen auf, und was ihr in diesem Gespräch klärt, fließt in die vier Materialien ein, die das Modell schreibt. Fehlen Arbeitsstände, rate der Person, sie vorher zu bestätigen, auch den Arbeitsstand dieses Schritts.
Auf Wunsch erstellst du auch kleinere Hilfen:
- Karteikarten: drei bis sieben Karten, je mit einer Kernbotschaft, einem Beleg oder Beispiel und einem Übergang.
@@ -1255,6 +1255,12 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1231621
-- The lab writes no press releases or other PR texts, and it checks no facts. It replaces neither your own expert review nor the legal and data protection advice of your institution, and it makes no political or normative decision for you. For a quick text, use the chat or another assistant of AI Studio.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1231621082::INFORMAL"] = "The lab writes no press releases or other PR texts, and it checks no facts. It replaces neither your own expert review nor the legal and data protection advice of your institution, and it makes no political or normative decision for you. For a quick text, use the chat or another assistant of AI Studio."
-- In the last step, let the lab create your materials from your confirmed work states: a reflection folder, a position paper, a conversation guide, questions and answers, and your open points. You check, edit, and confirm each of them, and then export it as a document.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1266652635"] = "In the last step, let the lab create your materials from your confirmed work states: a reflection folder, a position paper, a conversation guide, questions and answers, and your open points. You check, edit, and confirm each of them, and then export it as a document."
-- In the last step, let the lab create your materials from your confirmed work states: a reflection folder, a position paper, a conversation guide, questions and answers, and your open points. You check, edit, and confirm each of them, and then export it as a document.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1266652635::INFORMAL"] = "In the last step, let the lab create your materials from your confirmed work states: a reflection folder, a position paper, a conversation guide, questions and answers, and your open points. You check, edit, and confirm each of them, and then export it as a document."
-- You keep the decision about which position you take.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1509612483"] = "You keep the decision about which position you take."
@@ -1504,6 +1510,240 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLPROMPTOVERRIDENOTICE::
-- The lab currently uses experimental instructions from its test folder. You can switch them off in the options of the lab.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLPROMPTOVERRIDENOTICE::T1719028521::INFORMAL"] = "The lab currently uses experimental instructions from its test folder. You can switch them off in the options of the lab."
-- No confirmed work state.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T1085223273"] = "No confirmed work state."
-- The details of this step changed after this confirmation.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T116735836"] = "The details of this step changed after this confirmation."
-- Appendix: the conversations
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T1392283909"] = "Appendix: the conversations"
-- Image
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T1494001562"] = "Image"
-- No confirmed work state names open questions.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T1524103624"] = "No confirmed work state names open questions."
-- Open questions
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T2962485044"] = "Open questions"
-- You
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3049115964"] = "You"
-- You
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3049115964::INFORMAL"] = "You"
-- No material was added.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3104633786"] = "No material was added."
-- Lab
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3303746196"] = "Lab"
-- Material
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3419754368"] = "Material"
-- Recording
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3881628172"] = "Recording"
-- Version {0}, confirmed on {1}.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3926589642"] = "Version {0}, confirmed on {1}."
-- Left out, as it may contain personal disclosures.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3986361996"] = "Left out, as it may contain personal disclosures."
-- Document
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T4165204724"] = "Document"
-- An earlier step changed after this confirmation.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T4271561391"] = "An earlier step changed after this confirmation."
-- The file '{0}' in the test folder of the BeyondFacts Lab contains the placeholder '{1}', which the lab does not fill in this file. Please correct the file and try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T1150375027"] = "The file '{0}' in the test folder of the BeyondFacts Lab contains the placeholder '{1}', which the lab does not fill in this file. Please correct the file and try again."
-- The file '{0}' in the test folder of the BeyondFacts Lab contains the placeholder '{1}', which the lab does not fill in this file. Please correct the file and try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T1150375027::INFORMAL"] = "The file '{0}' in the test folder of the BeyondFacts Lab contains the placeholder '{1}', which the lab does not fill in this file. Please correct the file and try again."
-- AI Studio could not create this material. Please try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T1258513697"] = "AI Studio could not create this material. Please try again."
-- AI Studio could not create this material. Please try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T1258513697::INFORMAL"] = "AI Studio could not create this material. Please try again."
-- The model did not write this material. Please try again, or try another provider.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T2403507896"] = "The model did not write this material. Please try again, or try another provider."
-- The model did not write this material. Please try again, or try another provider.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T2403507896::INFORMAL"] = "The model did not write this material. Please try again, or try another provider."
-- Critical questions from the test situation, your approaches to answering them, and the points on which you have no reliable answer.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T1198530903"] = "Critical questions from the test situation, your approaches to answering them, and the points on which you have no reliable answer."
-- Critical questions from the test situation, your approaches to answering them, and the points on which you have no reliable answer.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T1198530903::INFORMAL"] = "Critical questions from the test situation, your approaches to answering them, and the points on which you have no reliable answer."
-- The opening, your key messages, questions to others, and wordings for uncertainty or disagreement. You can adapt it for a talk, a pitch, or a hearing.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3304526288"] = "The opening, your key messages, questions to others, and wordings for uncertainty or disagreement. You can adapt it for a talk, a pitch, or a hearing."
-- The opening, your key messages, questions to others, and wordings for uncertainty or disagreement. You can adapt it for a talk, a pitch, or a hearing.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3304526288::INFORMAL"] = "The opening, your key messages, questions to others, and wordings for uncertainty or disagreement. You can adapt it for a talk, a pitch, or a hearing."
-- Reflection folder
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3525062904"] = "Reflection folder"
-- All your confirmed work states, your material, the open questions, and your revisions, word for word. If you like, with the complete conversations as an appendix.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3690314691"] = "All your confirmed work states, your material, the open questions, and your revisions, word for word. If you like, with the complete conversations as an appendix."
-- All your confirmed work states, your material, the open questions, and your revisions, word for word. If you like, with the complete conversations as an appendix.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3690314691::INFORMAL"] = "All your confirmed work states, your material, the open questions, and your revisions, word for word. If you like, with the complete conversations as an appendix."
-- Open points and next steps
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3873392021"] = "Open points and next steps"
-- Position paper
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3950911696"] = "Position paper"
-- One page on what you stand for and why: your key statements, your reasons, the trade-offs between values, and the limits of your expertise.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T4085659087"] = "One page on what you stand for and why: your key statements, your reasons, the trade-offs between values, and the limits of your expertise."
-- One page on what you stand for and why: your key statements, your reasons, the trade-offs between values, and the limits of your expertise.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T4085659087::INFORMAL"] = "One page on what you stand for and why: your key statements, your reasons, the trade-offs between values, and the limits of your expertise."
-- Conversation guide
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T4171886338"] = "Conversation guide"
-- Questions and answers
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T704553916"] = "Questions and answers"
-- What you still have to research, clarify with others, or decide yourself before you appear.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T83625072"] = "What you still have to research, clarify with others, or decide yourself before you appear."
-- What you still have to research, clarify with others, or decide yourself before you appear.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T83625072::INFORMAL"] = "What you still have to research, clarify with others, or decide yourself before you appear."
-- The lab writes this material
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1161855660"] = "The lab writes this material"
-- Stop
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1266644741"] = "Stop"
-- You confirmed this material on {0}.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1463626379"] = "You confirmed this material on {0}."
-- You confirmed this material on {0}.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1463626379::INFORMAL"] = "You confirmed this material on {0}."
-- AI Studio cannot open this material. Its file may be damaged, or a newer version of AI Studio stored it. AI Studio leaves the file unchanged.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1470884556"] = "AI Studio cannot open this material. Its file may be damaged, or a newer version of AI Studio stored it. AI Studio leaves the file unchanged."
-- AI Studio cannot open this material. Its file may be damaged, or a newer version of AI Studio stored it. AI Studio leaves the file unchanged.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1470884556::INFORMAL"] = "AI Studio cannot open this material. Its file may be damaged, or a newer version of AI Studio stored it. AI Studio leaves the file unchanged."
-- Replace the drafts you have not confirmed yet? Materials you confirmed stay until you confirm their new drafts.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1551694648"] = "Replace the drafts you have not confirmed yet? Materials you confirmed stay until you confirm their new drafts."
-- Replace the drafts you have not confirmed yet? Materials you confirmed stay until you confirm their new drafts.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1551694648::INFORMAL"] = "Replace the drafts you have not confirmed yet? Materials you confirmed stay until you confirm their new drafts."
-- A work state changed since the lab wrote this draft. You can create it anew.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1597401023"] = "A work state changed since the lab wrote this draft. You can create it anew."
-- A work state changed since the lab wrote this draft. You can create it anew.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1597401023::INFORMAL"] = "A work state changed since the lab wrote this draft. You can create it anew."
-- The lab writes these materials from your confirmed work states. Check and edit each of them, and confirm it. Then you can export it as a document.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T182456751"] = "The lab writes these materials from your confirmed work states. Check and edit each of them, and confirm it. Then you can export it as a document."
-- The lab writes these materials from your confirmed work states. Check and edit each of them, and confirm it. Then you can export it as a document.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T182456751::INFORMAL"] = "The lab writes these materials from your confirmed work states. Check and edit each of them, and confirm it. Then you can export it as a document."
-- AI Studio could not export this material. Please try another format.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T195200475"] = "AI Studio could not export this material. Please try another format."
-- AI Studio could not export this material. Please try another format.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T195200475::INFORMAL"] = "AI Studio could not export this material. Please try another format."
-- Cannot be opened
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1981873292"] = "Cannot be opened"
-- These steps have no confirmed work state yet: {0}. The materials use only what you confirmed and name what is still open.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2174778813"] = "These steps have no confirmed work state yet: {0}. The materials use only what you confirmed and name what is still open."
-- These steps have no confirmed work state yet: {0}. The materials use only what you confirmed and name what is still open.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2174778813::INFORMAL"] = "These steps have no confirmed work state yet: {0}. The materials use only what you confirmed and name what is still open."
-- Discard draft
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2273967454"] = "Discard draft"
-- Draft
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2313908524"] = "Draft"
-- What would you like to take away?
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2505178919"] = "What would you like to take away?"
-- What would you like to take away?
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2505178919::INFORMAL"] = "What would you like to take away?"
-- Draft, not confirmed yet
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2553562678"] = "Draft, not confirmed yet"
-- Create
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2567824509"] = "Create"
-- Not created yet
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2679230892"] = "Not created yet"
-- Confirm
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2709768687"] = "Confirm"
-- A work state changed since you confirmed this material. Please create it anew, or check whether it still fits.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2881263992"] = "A work state changed since you confirmed this material. Please create it anew, or check whether it still fits."
-- A work state changed since you confirmed this material. Please create it anew, or check whether it still fits.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2881263992::INFORMAL"] = "A work state changed since you confirmed this material. Please create it anew, or check whether it still fits."
-- Add the conversations as an appendix
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3185544181"] = "Add the conversations as an appendix"
-- Add the conversations as an appendix
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3185544181::INFORMAL"] = "Add the conversations as an appendix"
-- Being written
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3204128327"] = "Being written"
-- Edit
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3267849393"] = "Edit"
-- AI Studio could not save this material. Please try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3460571754"] = "AI Studio could not save this material. Please try again."
-- AI Studio could not save this material. Please try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3460571754::INFORMAL"] = "AI Studio could not save this material. Please try again."
-- Create anew
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3560413436"] = "Create anew"
-- Export
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3898821075"] = "Export"
-- Create all materials in parallel
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3926195314"] = "Create all materials in parallel"
-- Include personal disclosures
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T4086721095"] = "Include personal disclosures"
-- Include personal disclosures
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T4086721095::INFORMAL"] = "Include personal disclosures"
-- Outdated
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T724820205"] = "Outdated"
-- Show preview
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T934952176"] = "Show preview"
-- Confirmed
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T942512558"] = "Confirmed"
-- Test situation
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLSTEPEXTENSIONS::T1049923473"] = "Test situation"
@@ -12385,9 +12625,6 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T613888204"] = "Translation"
-- Rewrite and improve a given text for a chosen style.
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T722167136"] = "Rewrite and improve a given text for a chosen style."
-- Learning
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T755590027"] = "Learning"
-- Bias of the Day
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T782102948"] = "Bias of the Day"
@@ -12403,6 +12640,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T892147062"] = "View and filter AI
-- Localization
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T897888480"] = "Localization"
-- Learning & Reflecting
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T912918956"] = "Learning & Reflecting"
-- Turn texts and documents into slides, also as a PowerPoint file in the design of your template.
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T943132958"] = "Turn texts and documents into slides, also as a PowerPoint file in the design of your template."
@@ -14221,8 +14461,8 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T3802462536"] = "
-- Select the assistant category
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T4193824894"] = "Select the assistant category"
-- Learning
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T755590027"] = "Learning"
-- Learning & Reflecting
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T912918956"] = "Learning & Reflecting"
-- This assistant is already running. AI Studio opens the running session instead.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTLAUNCH::ASSISTANTLAUNCHSERVICE::T2575715765"] = "This assistant is already running. AI Studio opens the running session instead."
@@ -68,7 +68,7 @@
<AssistantBlock TSettings="SettingsDialogVisualBriefing" Component="Components.VISUAL_BRIEFING_ASSISTANT" RequiredPreviewFeature="Components.VISUAL_BRIEFING_ASSISTANT.RequiredPreviewFeature" Name="@T("Visual Briefing Assistant")" Description="@T("Turn documents, data, images, audio, and video into an audience-ready interactive briefing.")" Icon="@Icons.Material.Filled.DashboardCustomize" Link="@Routes.ASSISTANT_VISUAL_BRIEFING" />
</AssistantCategoryBlock>
<AssistantCategoryBlock Title="@T("Learning")">
<AssistantCategoryBlock Title="@T("Learning & Reflecting")">
<AssistantBlock TSettings="SettingsDialogAssistantBias" Component="Components.BIAS_DAY_ASSISTANT" Name="@T("Bias of the Day")" Description="@T("Learn about one cognitive bias every day.")" Icon="@Icons.Material.Filled.Psychology" Link="@Routes.ASSISTANT_BIAS"/>
<AssistantBlock TSettings="SettingsDialogBeyondFactsLab" Component="Components.BEYOND_FACTS_LAB_ASSISTANT" RequiredPreviewFeature="Components.BEYOND_FACTS_LAB_ASSISTANT.RequiredPreviewFeature" Name="@T("BeyondFacts Lab")" Description="@T("Prepare step by step for a challenging appearance as a researcher, e.g., a panel discussion or an interview.")" Icon="@Icons.Material.Filled.RecordVoiceOver" Link="@Routes.ASSISTANT_BEYOND_FACTS_LAB"/>
</AssistantCategoryBlock>
@@ -1257,6 +1257,12 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1231621
-- The lab writes no press releases or other PR texts, and it checks no facts. It replaces neither your own expert review nor the legal and data protection advice of your institution, and it makes no political or normative decision for you. For a quick text, use the chat or another assistant of AI Studio.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1231621082::INFORMAL"] = "Das Lab schreibt keine Pressemitteilungen oder anderen PR-Texte und prüft keine Fakten. Es ersetzt weder deine eigene fachliche Prüfung noch die Rechts- und Datenschutzberatung deiner Institution, und es nimmt dir keine politische oder normative Entscheidung ab. Für einen schnellen Text nutze den Chat oder einen anderen Assistenten von AI Studio."
-- In the last step, let the lab create your materials from your confirmed work states: a reflection folder, a position paper, a conversation guide, questions and answers, and your open points. You check, edit, and confirm each of them, and then export it as a document.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1266652635"] = "Lassen Sie im letzten Schritt das Lab aus Ihren bestätigten Arbeitsständen Ihre Materialien erstellen: eine Reflexionsmappe, ein Positionsblatt, einen Gesprächsleitfaden, Fragen und Antwortansätze sowie Ihre offenen Punkte. Sie prüfen, bearbeiten und bestätigen jedes davon und exportieren es dann als Dokument."
-- In the last step, let the lab create your materials from your confirmed work states: a reflection folder, a position paper, a conversation guide, questions and answers, and your open points. You check, edit, and confirm each of them, and then export it as a document.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1266652635::INFORMAL"] = "Lass im letzten Schritt das Lab aus deinen bestätigten Arbeitsständen deine Materialien erstellen: eine Reflexionsmappe, ein Positionsblatt, einen Gesprächsleitfaden, Fragen und Antwortansätze sowie deine offenen Punkte. Du prüfst, bearbeitest und bestätigst jedes davon und exportierst es dann als Dokument."
-- You keep the decision about which position you take.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1509612483"] = "Sie behalten die Entscheidung darüber, welche Position Sie vertreten."
@@ -1506,6 +1512,240 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLPROMPTOVERRIDENOTICE::
-- The lab currently uses experimental instructions from its test folder. You can switch them off in the options of the lab.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLPROMPTOVERRIDENOTICE::T1719028521::INFORMAL"] = "Das Lab verwendet derzeit experimentelle Anweisungen aus seinem Testordner. Du kannst sie in den Optionen des Labs deaktivieren."
-- No confirmed work state.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T1085223273"] = "Kein bestätigter Arbeitsstand."
-- The details of this step changed after this confirmation.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T116735836"] = "Die Angaben dieses Schritts haben sich nach dieser Bestätigung geändert."
-- Appendix: the conversations
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T1392283909"] = "Anhang: die Gespräche"
-- Image
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T1494001562"] = "Bild"
-- No confirmed work state names open questions.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T1524103624"] = "Kein bestätigter Arbeitsstand nennt offene Fragen."
-- Open questions
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T2962485044"] = "Offene Fragen"
-- You
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3049115964"] = "Sie"
-- You
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3049115964::INFORMAL"] = "Du"
-- No material was added.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3104633786"] = "Es wurde kein Material hinzugefügt."
-- Lab
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3303746196"] = "Lab"
-- Material
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3419754368"] = "Material"
-- Recording
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3881628172"] = "Aufnahme"
-- Version {0}, confirmed on {1}.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3926589642"] = "Version {0}, bestätigt am {1}."
-- Left out, as it may contain personal disclosures.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3986361996"] = "Ausgelassen, da es persönliche Angaben enthalten kann."
-- Document
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T4165204724"] = "Dokument"
-- An earlier step changed after this confirmation.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T4271561391"] = "Ein früherer Schritt hat sich nach dieser Bestätigung geändert."
-- The file '{0}' in the test folder of the BeyondFacts Lab contains the placeholder '{1}', which the lab does not fill in this file. Please correct the file and try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T1150375027"] = "Die Datei „{0}“ im Testordner des BeyondFacts Labs enthält den Platzhalter „{1}“, den das Lab in dieser Datei nicht ausfüllt. Bitte korrigieren Sie die Datei und versuchen Sie es erneut."
-- The file '{0}' in the test folder of the BeyondFacts Lab contains the placeholder '{1}', which the lab does not fill in this file. Please correct the file and try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T1150375027::INFORMAL"] = "Die Datei „{0}“ im Testordner des BeyondFacts Labs enthält den Platzhalter „{1}“, den das Lab in dieser Datei nicht ausfüllt. Bitte korrigiere die Datei und versuche es erneut."
-- AI Studio could not create this material. Please try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T1258513697"] = "AI Studio konnte dieses Material nicht erstellen. Bitte versuchen Sie es erneut."
-- AI Studio could not create this material. Please try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T1258513697::INFORMAL"] = "AI Studio konnte dieses Material nicht erstellen. Bitte versuche es erneut."
-- The model did not write this material. Please try again, or try another provider.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T2403507896"] = "Das Modell hat dieses Material nicht geschrieben. Bitte versuchen Sie es erneut, oder wählen Sie einen anderen Anbieter aus."
-- The model did not write this material. Please try again, or try another provider.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T2403507896::INFORMAL"] = "Das Modell hat dieses Material nicht geschrieben. Bitte versuche es erneut, oder wähle einen anderen Anbieter aus."
-- Critical questions from the test situation, your approaches to answering them, and the points on which you have no reliable answer.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T1198530903"] = "Kritische Nachfragen aus der Testsituation, Ihre Ansätze, sie zu beantworten, und die Punkte, auf die Sie keine belastbare Antwort haben."
-- Critical questions from the test situation, your approaches to answering them, and the points on which you have no reliable answer.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T1198530903::INFORMAL"] = "Kritische Nachfragen aus der Testsituation, deine Ansätze, sie zu beantworten, und die Punkte, auf die du keine belastbare Antwort hast."
-- The opening, your key messages, questions to others, and wordings for uncertainty or disagreement. You can adapt it for a talk, a pitch, or a hearing.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3304526288"] = "Der Einstieg, Ihre zentralen Botschaften, Fragen an andere und Formulierungen für Unsicherheit oder Meinungsverschiedenheiten. Sie können ihn für einen Vortrag, einen Pitch oder eine Anhörung anpassen."
-- The opening, your key messages, questions to others, and wordings for uncertainty or disagreement. You can adapt it for a talk, a pitch, or a hearing.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3304526288::INFORMAL"] = "Der Einstieg, deine zentralen Botschaften, Fragen an andere und Formulierungen für Unsicherheit oder Meinungsverschiedenheiten. Du kannst ihn für einen Vortrag, einen Pitch oder eine Anhörung anpassen."
-- Reflection folder
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3525062904"] = "Reflexionsmappe"
-- All your confirmed work states, your material, the open questions, and your revisions, word for word. If you like, with the complete conversations as an appendix.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3690314691"] = "Alle Ihre bestätigten Arbeitsstände, Ihr Material, die offenen Fragen und Ihre Überarbeitungen, wörtlich. Auf Wunsch mit den vollständigen Gesprächen als Anhang."
-- All your confirmed work states, your material, the open questions, and your revisions, word for word. If you like, with the complete conversations as an appendix.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3690314691::INFORMAL"] = "Alle deine bestätigten Arbeitsstände, dein Material, die offenen Fragen und deine Überarbeitungen, wörtlich. Auf Wunsch mit den vollständigen Gesprächen als Anhang."
-- Open points and next steps
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3873392021"] = "Offene Punkte und nächste Schritte"
-- Position paper
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3950911696"] = "Positionsblatt"
-- One page on what you stand for and why: your key statements, your reasons, the trade-offs between values, and the limits of your expertise.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T4085659087"] = "Eine Seite dazu, was Sie vertreten und warum: Ihre zentralen Aussagen, Ihre Begründungen, die Abwägungen zwischen Werten und die Grenzen Ihrer Expertise."
-- One page on what you stand for and why: your key statements, your reasons, the trade-offs between values, and the limits of your expertise.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T4085659087::INFORMAL"] = "Eine Seite dazu, was du vertrittst und warum: deine zentralen Aussagen, deine Begründungen, die Abwägungen zwischen Werten und die Grenzen deiner Expertise."
-- Conversation guide
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T4171886338"] = "Gesprächsleitfaden"
-- Questions and answers
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T704553916"] = "Fragen und Antwortansätze"
-- What you still have to research, clarify with others, or decide yourself before you appear.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T83625072"] = "Was Sie vor Ihrem Auftritt noch recherchieren, mit anderen klären oder selbst entscheiden müssen."
-- What you still have to research, clarify with others, or decide yourself before you appear.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T83625072::INFORMAL"] = "Was du vor deinem Auftritt noch recherchieren, mit anderen klären oder selbst entscheiden musst."
-- The lab writes this material
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1161855660"] = "Das Lab schreibt dieses Material"
-- Stop
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1266644741"] = "Stoppen"
-- You confirmed this material on {0}.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1463626379"] = "Sie haben dieses Material am {0} bestätigt."
-- You confirmed this material on {0}.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1463626379::INFORMAL"] = "Du hast dieses Material am {0} bestätigt."
-- AI Studio cannot open this material. Its file may be damaged, or a newer version of AI Studio stored it. AI Studio leaves the file unchanged.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1470884556"] = "AI Studio kann dieses Material nicht öffnen. Seine Datei ist möglicherweise beschädigt oder wurde mit einer neueren Version von AI Studio gespeichert. AI Studio lässt die Datei unverändert."
-- AI Studio cannot open this material. Its file may be damaged, or a newer version of AI Studio stored it. AI Studio leaves the file unchanged.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1470884556::INFORMAL"] = "AI Studio kann dieses Material nicht öffnen. Seine Datei ist möglicherweise beschädigt oder wurde mit einer neueren Version von AI Studio gespeichert. AI Studio lässt die Datei unverändert."
-- Replace the drafts you have not confirmed yet? Materials you confirmed stay until you confirm their new drafts.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1551694648"] = "Möchten Sie die noch nicht bestätigten Entwürfe ersetzen? Bestätigte Materialien bleiben erhalten, bis Sie die neuen Entwürfe bestätigen."
-- Replace the drafts you have not confirmed yet? Materials you confirmed stay until you confirm their new drafts.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1551694648::INFORMAL"] = "Möchtest du die noch nicht bestätigten Entwürfe ersetzen? Bestätigte Materialien bleiben erhalten, bis du die neuen Entwürfe bestätigst."
-- A work state changed since the lab wrote this draft. You can create it anew.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1597401023"] = "Seit das Lab diesen Entwurf geschrieben hat, hat sich ein Arbeitsstand geändert. Sie können ihn neu erstellen."
-- A work state changed since the lab wrote this draft. You can create it anew.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1597401023::INFORMAL"] = "Seit das Lab diesen Entwurf geschrieben hat, hat sich ein Arbeitsstand geändert. Du kannst ihn neu erstellen."
-- The lab writes these materials from your confirmed work states. Check and edit each of them, and confirm it. Then you can export it as a document.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T182456751"] = "Das Lab schreibt diese Materialien aus Ihren bestätigten Arbeitsständen. Prüfen und bearbeiten Sie jedes davon, und bestätigen Sie es. Danach können Sie es als Dokument exportieren."
-- The lab writes these materials from your confirmed work states. Check and edit each of them, and confirm it. Then you can export it as a document.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T182456751::INFORMAL"] = "Das Lab schreibt diese Materialien aus deinen bestätigten Arbeitsständen. Prüfe und bearbeite jedes davon, und bestätige es. Danach kannst du es als Dokument exportieren."
-- AI Studio could not export this material. Please try another format.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T195200475"] = "AI Studio konnte dieses Material nicht exportieren. Bitte versuchen Sie es mit einem anderen Format."
-- AI Studio could not export this material. Please try another format.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T195200475::INFORMAL"] = "AI Studio konnte dieses Material nicht exportieren. Bitte versuche es mit einem anderen Format."
-- Cannot be opened
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1981873292"] = "Kann nicht geöffnet werden"
-- These steps have no confirmed work state yet: {0}. The materials use only what you confirmed and name what is still open.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2174778813"] = "Diese Schritte haben noch keinen bestätigten Arbeitsstand: {0}. Die Materialien verwenden nur, was Sie bestätigt haben, und nennen, was noch offen ist."
-- These steps have no confirmed work state yet: {0}. The materials use only what you confirmed and name what is still open.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2174778813::INFORMAL"] = "Diese Schritte haben noch keinen bestätigten Arbeitsstand: {0}. Die Materialien verwenden nur, was du bestätigt hast, und nennen, was noch offen ist."
-- Discard draft
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2273967454"] = "Entwurf verwerfen"
-- Draft
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2313908524"] = "Entwurf"
-- What would you like to take away?
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2505178919"] = "Was möchten Sie mitnehmen?"
-- What would you like to take away?
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2505178919::INFORMAL"] = "Was möchtest du mitnehmen?"
-- Draft, not confirmed yet
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2553562678"] = "Entwurf, noch nicht bestätigt"
-- Create
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2567824509"] = "Erstellen"
-- Not created yet
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2679230892"] = "Noch nicht erstellt"
-- Confirm
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2709768687"] = "Bestätigen"
-- A work state changed since you confirmed this material. Please create it anew, or check whether it still fits.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2881263992"] = "Seit Sie dieses Material bestätigt haben, hat sich ein Arbeitsstand geändert. Bitte erstellen Sie es neu, oder prüfen Sie, ob es noch passt."
-- A work state changed since you confirmed this material. Please create it anew, or check whether it still fits.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2881263992::INFORMAL"] = "Seit du dieses Material bestätigt hast, hat sich ein Arbeitsstand geändert. Bitte erstelle es neu, oder prüfe, ob es noch passt."
-- Add the conversations as an appendix
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3185544181"] = "Gespräche als Anhang aufnehmen"
-- Add the conversations as an appendix
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3185544181::INFORMAL"] = "Gespräche als Anhang aufnehmen"
-- Being written
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3204128327"] = "Wird geschrieben"
-- Edit
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3267849393"] = "Bearbeiten"
-- AI Studio could not save this material. Please try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3460571754"] = "AI Studio konnte dieses Material nicht speichern. Bitte versuchen Sie es erneut."
-- AI Studio could not save this material. Please try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3460571754::INFORMAL"] = "AI Studio konnte dieses Material nicht speichern. Bitte versuche es erneut."
-- Create anew
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3560413436"] = "Neu erstellen"
-- Export
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3898821075"] = "Exportieren"
-- Create all materials in parallel
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3926195314"] = "Alle Materialien parallel erstellen"
-- Include personal disclosures
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T4086721095"] = "Persönliche Angaben aufnehmen"
-- Include personal disclosures
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T4086721095::INFORMAL"] = "Persönliche Angaben aufnehmen"
-- Outdated
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T724820205"] = "Veraltet"
-- Show preview
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T934952176"] = "Vorschau anzeigen"
-- Confirmed
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T942512558"] = "Bestätigt"
-- Test situation
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLSTEPEXTENSIONS::T1049923473"] = "Testsituation"
@@ -12387,9 +12627,6 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T613888204"] = "Übersetzung"
-- Rewrite and improve a given text for a chosen style.
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T722167136"] = "Einen gegebenen Text für einen gewählten Stil umformulieren und verbessern."
-- Learning
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T755590027"] = "Lernen"
-- Bias of the Day
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T782102948"] = "Vorurteil des Tages"
@@ -12405,6 +12642,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T892147062"] = "AI-Studio-Protokol
-- Localization
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T897888480"] = "Lokalisierung"
-- Learning & Reflecting
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T912918956"] = "Lernen & Reflektieren"
-- Turn texts and documents into slides, also as a PowerPoint file in the design of your template.
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T943132958"] = "Verwandeln Sie Texte und Dokumente in Folien, auch als PowerPoint-Datei im Design Ihrer Vorlage."
@@ -14223,8 +14463,8 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T3802462536"] = "
-- Select the assistant category
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T4193824894"] = "Assistentenkategorie auswählen"
-- Learning
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T755590027"] = "Lernen"
-- Learning & Reflecting
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T912918956"] = "Lernen & Reflektieren"
-- This assistant is already running. AI Studio opens the running session instead.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTLAUNCH::ASSISTANTLAUNCHSERVICE::T2575715765"] = "Dieser Assistent läuft bereits. AI Studio öffnet stattdessen die laufende Sitzung."
@@ -1257,6 +1257,12 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1231621
-- The lab writes no press releases or other PR texts, and it checks no facts. It replaces neither your own expert review nor the legal and data protection advice of your institution, and it makes no political or normative decision for you. For a quick text, use the chat or another assistant of AI Studio.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1231621082::INFORMAL"] = "The lab writes no press releases or other PR texts, and it checks no facts. It replaces neither your own expert review nor the legal and data protection advice of your institution, and it makes no political or normative decision for you. For a quick text, use the chat or another assistant of AI Studio."
-- In the last step, let the lab create your materials from your confirmed work states: a reflection folder, a position paper, a conversation guide, questions and answers, and your open points. You check, edit, and confirm each of them, and then export it as a document.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1266652635"] = "In the last step, let the lab create your materials from your confirmed work states: a reflection folder, a position paper, a conversation guide, questions and answers, and your open points. You check, edit, and confirm each of them, and then export it as a document."
-- In the last step, let the lab create your materials from your confirmed work states: a reflection folder, a position paper, a conversation guide, questions and answers, and your open points. You check, edit, and confirm each of them, and then export it as a document.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1266652635::INFORMAL"] = "In the last step, let the lab create your materials from your confirmed work states: a reflection folder, a position paper, a conversation guide, questions and answers, and your open points. You check, edit, and confirm each of them, and then export it as a document."
-- You keep the decision about which position you take.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLINTRODUCTION::T1509612483"] = "You keep the decision about which position you take."
@@ -1506,6 +1512,240 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLPROMPTOVERRIDENOTICE::
-- The lab currently uses experimental instructions from its test folder. You can switch them off in the options of the lab.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLPROMPTOVERRIDENOTICE::T1719028521::INFORMAL"] = "The lab currently uses experimental instructions from its test folder. You can switch them off in the options of the lab."
-- No confirmed work state.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T1085223273"] = "No confirmed work state."
-- The details of this step changed after this confirmation.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T116735836"] = "The details of this step changed after this confirmation."
-- Appendix: the conversations
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T1392283909"] = "Appendix: the conversations"
-- Image
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T1494001562"] = "Image"
-- No confirmed work state names open questions.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T1524103624"] = "No confirmed work state names open questions."
-- Open questions
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T2962485044"] = "Open questions"
-- You
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3049115964"] = "You"
-- You
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3049115964::INFORMAL"] = "You"
-- No material was added.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3104633786"] = "No material was added."
-- Lab
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3303746196"] = "Lab"
-- Material
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3419754368"] = "Material"
-- Recording
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3881628172"] = "Recording"
-- Version {0}, confirmed on {1}.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3926589642"] = "Version {0}, confirmed on {1}."
-- Left out, as it may contain personal disclosures.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T3986361996"] = "Left out, as it may contain personal disclosures."
-- Document
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T4165204724"] = "Document"
-- An earlier step changed after this confirmation.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLREFLECTIONFOLDER::T4271561391"] = "An earlier step changed after this confirmation."
-- The file '{0}' in the test folder of the BeyondFacts Lab contains the placeholder '{1}', which the lab does not fill in this file. Please correct the file and try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T1150375027"] = "The file '{0}' in the test folder of the BeyondFacts Lab contains the placeholder '{1}', which the lab does not fill in this file. Please correct the file and try again."
-- The file '{0}' in the test folder of the BeyondFacts Lab contains the placeholder '{1}', which the lab does not fill in this file. Please correct the file and try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T1150375027::INFORMAL"] = "The file '{0}' in the test folder of the BeyondFacts Lab contains the placeholder '{1}', which the lab does not fill in this file. Please correct the file and try again."
-- AI Studio could not create this material. Please try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T1258513697"] = "AI Studio could not create this material. Please try again."
-- AI Studio could not create this material. Please try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T1258513697::INFORMAL"] = "AI Studio could not create this material. Please try again."
-- The model did not write this material. Please try again, or try another provider.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T2403507896"] = "The model did not write this material. Please try again, or try another provider."
-- The model did not write this material. Please try again, or try another provider.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTGENERATOR::T2403507896::INFORMAL"] = "The model did not write this material. Please try again, or try another provider."
-- Critical questions from the test situation, your approaches to answering them, and the points on which you have no reliable answer.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T1198530903"] = "Critical questions from the test situation, your approaches to answering them, and the points on which you have no reliable answer."
-- Critical questions from the test situation, your approaches to answering them, and the points on which you have no reliable answer.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T1198530903::INFORMAL"] = "Critical questions from the test situation, your approaches to answering them, and the points on which you have no reliable answer."
-- The opening, your key messages, questions to others, and wordings for uncertainty or disagreement. You can adapt it for a talk, a pitch, or a hearing.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3304526288"] = "The opening, your key messages, questions to others, and wordings for uncertainty or disagreement. You can adapt it for a talk, a pitch, or a hearing."
-- The opening, your key messages, questions to others, and wordings for uncertainty or disagreement. You can adapt it for a talk, a pitch, or a hearing.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3304526288::INFORMAL"] = "The opening, your key messages, questions to others, and wordings for uncertainty or disagreement. You can adapt it for a talk, a pitch, or a hearing."
-- Reflection folder
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3525062904"] = "Reflection folder"
-- All your confirmed work states, your material, the open questions, and your revisions, word for word. If you like, with the complete conversations as an appendix.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3690314691"] = "All your confirmed work states, your material, the open questions, and your revisions, word for word. If you like, with the complete conversations as an appendix."
-- All your confirmed work states, your material, the open questions, and your revisions, word for word. If you like, with the complete conversations as an appendix.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3690314691::INFORMAL"] = "All your confirmed work states, your material, the open questions, and your revisions, word for word. If you like, with the complete conversations as an appendix."
-- Open points and next steps
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3873392021"] = "Open points and next steps"
-- Position paper
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T3950911696"] = "Position paper"
-- One page on what you stand for and why: your key statements, your reasons, the trade-offs between values, and the limits of your expertise.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T4085659087"] = "One page on what you stand for and why: your key statements, your reasons, the trade-offs between values, and the limits of your expertise."
-- One page on what you stand for and why: your key statements, your reasons, the trade-offs between values, and the limits of your expertise.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T4085659087::INFORMAL"] = "One page on what you stand for and why: your key statements, your reasons, the trade-offs between values, and the limits of your expertise."
-- Conversation guide
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T4171886338"] = "Conversation guide"
-- Questions and answers
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T704553916"] = "Questions and answers"
-- What you still have to research, clarify with others, or decide yourself before you appear.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T83625072"] = "What you still have to research, clarify with others, or decide yourself before you appear."
-- What you still have to research, clarify with others, or decide yourself before you appear.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTKINDEXTENSIONS::T83625072::INFORMAL"] = "What you still have to research, clarify with others, or decide yourself before you appear."
-- The lab writes this material
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1161855660"] = "The lab writes this material"
-- Stop
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1266644741"] = "Stop"
-- You confirmed this material on {0}.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1463626379"] = "You confirmed this material on {0}."
-- You confirmed this material on {0}.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1463626379::INFORMAL"] = "You confirmed this material on {0}."
-- AI Studio cannot open this material. Its file may be damaged, or a newer version of AI Studio stored it. AI Studio leaves the file unchanged.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1470884556"] = "AI Studio cannot open this material. Its file may be damaged, or a newer version of AI Studio stored it. AI Studio leaves the file unchanged."
-- AI Studio cannot open this material. Its file may be damaged, or a newer version of AI Studio stored it. AI Studio leaves the file unchanged.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1470884556::INFORMAL"] = "AI Studio cannot open this material. Its file may be damaged, or a newer version of AI Studio stored it. AI Studio leaves the file unchanged."
-- Replace the drafts you have not confirmed yet? Materials you confirmed stay until you confirm their new drafts.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1551694648"] = "Replace the drafts you have not confirmed yet? Materials you confirmed stay until you confirm their new drafts."
-- Replace the drafts you have not confirmed yet? Materials you confirmed stay until you confirm their new drafts.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1551694648::INFORMAL"] = "Replace the drafts you have not confirmed yet? Materials you confirmed stay until you confirm their new drafts."
-- A work state changed since the lab wrote this draft. You can create it anew.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1597401023"] = "A work state changed since the lab wrote this draft. You can create it anew."
-- A work state changed since the lab wrote this draft. You can create it anew.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1597401023::INFORMAL"] = "A work state changed since the lab wrote this draft. You can create it anew."
-- The lab writes these materials from your confirmed work states. Check and edit each of them, and confirm it. Then you can export it as a document.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T182456751"] = "The lab writes these materials from your confirmed work states. Check and edit each of them, and confirm it. Then you can export it as a document."
-- The lab writes these materials from your confirmed work states. Check and edit each of them, and confirm it. Then you can export it as a document.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T182456751::INFORMAL"] = "The lab writes these materials from your confirmed work states. Check and edit each of them, and confirm it. Then you can export it as a document."
-- AI Studio could not export this material. Please try another format.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T195200475"] = "AI Studio could not export this material. Please try another format."
-- AI Studio could not export this material. Please try another format.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T195200475::INFORMAL"] = "AI Studio could not export this material. Please try another format."
-- Cannot be opened
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T1981873292"] = "Cannot be opened"
-- These steps have no confirmed work state yet: {0}. The materials use only what you confirmed and name what is still open.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2174778813"] = "These steps have no confirmed work state yet: {0}. The materials use only what you confirmed and name what is still open."
-- These steps have no confirmed work state yet: {0}. The materials use only what you confirmed and name what is still open.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2174778813::INFORMAL"] = "These steps have no confirmed work state yet: {0}. The materials use only what you confirmed and name what is still open."
-- Discard draft
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2273967454"] = "Discard draft"
-- Draft
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2313908524"] = "Draft"
-- What would you like to take away?
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2505178919"] = "What would you like to take away?"
-- What would you like to take away?
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2505178919::INFORMAL"] = "What would you like to take away?"
-- Draft, not confirmed yet
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2553562678"] = "Draft, not confirmed yet"
-- Create
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2567824509"] = "Create"
-- Not created yet
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2679230892"] = "Not created yet"
-- Confirm
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2709768687"] = "Confirm"
-- A work state changed since you confirmed this material. Please create it anew, or check whether it still fits.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2881263992"] = "A work state changed since you confirmed this material. Please create it anew, or check whether it still fits."
-- A work state changed since you confirmed this material. Please create it anew, or check whether it still fits.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T2881263992::INFORMAL"] = "A work state changed since you confirmed this material. Please create it anew, or check whether it still fits."
-- Add the conversations as an appendix
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3185544181"] = "Add the conversations as an appendix"
-- Add the conversations as an appendix
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3185544181::INFORMAL"] = "Add the conversations as an appendix"
-- Being written
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3204128327"] = "Being written"
-- Edit
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3267849393"] = "Edit"
-- AI Studio could not save this material. Please try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3460571754"] = "AI Studio could not save this material. Please try again."
-- AI Studio could not save this material. Please try again.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3460571754::INFORMAL"] = "AI Studio could not save this material. Please try again."
-- Create anew
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3560413436"] = "Create anew"
-- Export
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3898821075"] = "Export"
-- Create all materials in parallel
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T3926195314"] = "Create all materials in parallel"
-- Include personal disclosures
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T4086721095"] = "Include personal disclosures"
-- Include personal disclosures
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T4086721095::INFORMAL"] = "Include personal disclosures"
-- Outdated
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T724820205"] = "Outdated"
-- Show preview
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T934952176"] = "Show preview"
-- Confirmed
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLRESULTS::T942512558"] = "Confirmed"
-- Test situation
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BEYONDFACTSLAB::BFLSTEPEXTENSIONS::T1049923473"] = "Test situation"
@@ -12387,9 +12627,6 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T613888204"] = "Translation"
-- Rewrite and improve a given text for a chosen style.
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T722167136"] = "Rewrite and improve a given text for a chosen style."
-- Learning
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T755590027"] = "Learning"
-- Bias of the Day
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T782102948"] = "Bias of the Day"
@@ -12405,6 +12642,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T892147062"] = "View and filter AI
-- Localization
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T897888480"] = "Localization"
-- Learning & Reflecting
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T912918956"] = "Learning & Reflecting"
-- Turn texts and documents into slides, also as a PowerPoint file in the design of your template.
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T943132958"] = "Turn texts and documents into slides, also as a PowerPoint file in the design of your template."
@@ -14223,8 +14463,8 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T3802462536"] = "
-- Select the assistant category
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T4193824894"] = "Select the assistant category"
-- Learning
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T755590027"] = "Learning"
-- Learning & Reflecting
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T912918956"] = "Learning & Reflecting"
-- This assistant is already running. AI Studio opens the running session instead.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTLAUNCH::ASSISTANTLAUNCHSERVICE::T2575715765"] = "This assistant is already running. AI Studio opens the running session instead."
+1
View File
@@ -233,6 +233,7 @@ internal sealed class Program
builder.Services.AddSingleton<BeyondFactsLabStore>();
builder.Services.AddSingleton<BflConversationService>();
builder.Services.AddSingleton<BflWorkStateGenerator>();
builder.Services.AddSingleton<BflResultGenerator>();
builder.Services.AddSingleton<BflMaterialService>();
builder.Services.AddSingleton<PluginInstallService>();
builder.Services.AddSingleton<UpdatePolicy>();
@@ -16,7 +16,7 @@ public static class AssistantCategoryExtensions
AssistantCategory.BUSINESS => TB("Business"),
AssistantCategory.PRODUCTIVITY => TB("Productivity"),
AssistantCategory.DEVELOPMENT => TB("Software Development"),
AssistantCategory.LEARNING => TB("Learning"),
AssistantCategory.LEARNING => TB("Learning & Reflecting"),
AssistantCategory.AI_STUDIO => TB("AI Studio Development"),
AssistantCategory.OTHER => TB("Other"),