mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-05 07:07:21 +00:00
Added a SWOT analysis assistant (#1122)
Co-authored-by: hart_s3 <sabrina.hartmann@dlr.de>
This commit is contained in:
1 parent
6cb20fd75a
commit
060a2a5734
87 files changed
+4601
-45
No files matched your search
@@ -0,0 +1,181 @@
|
||||
using System.Text.Json;
|
||||
|
||||
using AIStudio.Assistants.SWOTAnalysis;
|
||||
|
||||
namespace AIStudio.Tests.Assistants.SWOTAnalysis;
|
||||
|
||||
[TestFixture]
|
||||
public sealed class SwotCategoryAnalysisResponseTests
|
||||
{
|
||||
[Test]
|
||||
public void TheFindingsOfACategoryAreReadAndTrimmed()
|
||||
{
|
||||
var result = CreateResult();
|
||||
result.Findings[0].Summary = " Experienced team ";
|
||||
|
||||
var parsed = SwotCategoryAnalysisResponseParser.TryParse(JsonSerializer.Serialize(result), out var parsedResult, out var issue);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(parsed, Is.True);
|
||||
Assert.That(issue, Is.Empty);
|
||||
Assert.That(parsedResult.EmptyMessage, Is.Empty);
|
||||
Assert.That(parsedResult.Findings.Single().Summary, Is.EqualTo("Experienced team"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AnAnswerWithoutJsonNamesTheProblemForTheModel()
|
||||
{
|
||||
var parsed = SwotCategoryAnalysisResponseParser.TryParse("I cannot analyze this category.", out _, out var issue);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(parsed, Is.False);
|
||||
Assert.That(issue, Does.Contain("no complete JSON object"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BrokenJsonNamesTheProblemForTheModel()
|
||||
{
|
||||
var parsed = SwotCategoryAnalysisResponseParser.TryParse("""{"findings": [{"summary": "Experienced team",}""", out _, out var issue);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(parsed, Is.False);
|
||||
Assert.That(issue, Is.Not.Empty);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ANullFieldIsRejectedRatherThanReadAsEmpty()
|
||||
{
|
||||
var parsed = SwotCategoryAnalysisResponseParser.TryParse("""{"empty_message": null, "findings": []}""", out _, out var issue);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(parsed, Is.False);
|
||||
Assert.That(issue, Does.StartWith("The JSON object cannot be read:"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ANullFindingIsLeftOut()
|
||||
{
|
||||
var parsed = SwotCategoryAnalysisResponseParser.TryParse("""{"empty_message": "", "findings": [null, {"summary": "Experienced team", "explanation": "Long tenure."}]}""", out var result, out _);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(parsed, Is.True);
|
||||
Assert.That(result.Findings.Single().Summary, Is.EqualTo("Experienced team"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AnUnsupportedCategoryRequiresAnExplanation()
|
||||
{
|
||||
var validEmptyResponse = JsonSerializer.Serialize(new SwotCategoryAnalysisResult
|
||||
{
|
||||
EmptyMessage = "The supplied material contains no evidence for this category.",
|
||||
});
|
||||
var invalidEmptyResponse = JsonSerializer.Serialize(new SwotCategoryAnalysisResult());
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SwotCategoryAnalysisResponseParser.TryParse(validEmptyResponse, out var result, out _), Is.True);
|
||||
Assert.That(result.Findings, Is.Empty);
|
||||
Assert.That(SwotCategoryAnalysisResponseParser.TryParse(invalidEmptyResponse, out _, out var issue), Is.False);
|
||||
Assert.That(issue, Does.Contain("empty_message"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FindingsRejectAnEmptyMessageOrMissingEvidenceExplanation()
|
||||
{
|
||||
var result = CreateResult();
|
||||
result.EmptyMessage = "No evidence.";
|
||||
var responseWithContradictoryEmptyMessage = JsonSerializer.Serialize(result);
|
||||
|
||||
result.EmptyMessage = string.Empty;
|
||||
result.Findings[0].Explanation = string.Empty;
|
||||
var responseWithoutExplanation = JsonSerializer.Serialize(result);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SwotCategoryAnalysisResponseParser.TryParse(responseWithContradictoryEmptyMessage, out _, out var contradictionIssue), Is.False);
|
||||
Assert.That(contradictionIssue, Does.Contain("Leave empty_message empty"));
|
||||
Assert.That(SwotCategoryAnalysisResponseParser.TryParse(responseWithoutExplanation, out _, out var explanationIssue), Is.False);
|
||||
Assert.That(explanationIssue, Is.EqualTo("Finding 1 has no explanation."));
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase("STRENGTHS", "strengths: internal positive factors")]
|
||||
[TestCase("WEAKNESSES", "weaknesses: internal negative factors")]
|
||||
[TestCase("OPPORTUNITIES", "opportunities: external positive factors")]
|
||||
[TestCase("THREATS", "threats: external negative factors")]
|
||||
public void TheSystemPromptAssignsExactlyOneCategory(string categoryName, string expectedDescription)
|
||||
{
|
||||
var category = Enum.Parse<SwotAnalysisCategory>(categoryName);
|
||||
var prompt = SwotCategoryAnalysis.BuildSystemPrompt(category, "Answer in German.");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(prompt, Does.Contain($"Analyze only {expectedDescription}."));
|
||||
Assert.That(prompt, Does.Contain("Do not return findings for another SWOT category."));
|
||||
Assert.That(prompt, Does.Contain("shared-research contains additional evidence"));
|
||||
Assert.That(prompt, Does.Contain("analysis-subject, contextual-knowledge, and\nshared-research"));
|
||||
Assert.That(prompt, Does.Contain("untrusted data"));
|
||||
Assert.That(prompt, Does.EndWith("Answer in German."));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TheCategoryRequestKeepsEveryInputInItsAssignedSection()
|
||||
{
|
||||
var request = SwotCategoryAnalysis.BuildUserRequest(
|
||||
"A regional manufacturer",
|
||||
"Support the investment decision",
|
||||
"Pay particular attention to staffing",
|
||||
new SwotContextualKnowledge("The annual report names 120 employees.", []),
|
||||
sharedResearch: "A market report documents increasing regional demand.");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(request, Does.Match("(?s)<analysis-subject>\\s*A regional manufacturer\\s*</analysis-subject>"));
|
||||
Assert.That(request, Does.Match("(?s)<analysis-goal>\\s*Support the investment decision\\s*</analysis-goal>"));
|
||||
Assert.That(request, Does.Match("(?s)<analysis-focus>\\s*Pay particular attention to staffing\\s*</analysis-focus>"));
|
||||
Assert.That(request, Does.Match("(?s)<contextual-knowledge>\\s*The annual report names 120 employees\\.\\s*</contextual-knowledge>"));
|
||||
Assert.That(request, Does.Match("(?s)<shared-research>\\s*A market report documents increasing regional demand\\.\\s*</shared-research>"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TheCategoryRequestOmitsEmptySharedResearch()
|
||||
{
|
||||
var request = SwotCategoryAnalysis.BuildUserRequest(
|
||||
"A regional manufacturer",
|
||||
"Support the investment decision",
|
||||
string.Empty,
|
||||
SwotContextualKnowledge.NONE);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(request, Does.Not.Contain("<shared-research>"));
|
||||
Assert.That(request, Does.Contain("No additional analysis focus was provided."));
|
||||
Assert.That(request, Does.Contain("No additional contextual knowledge was provided."));
|
||||
});
|
||||
}
|
||||
|
||||
private static SwotCategoryAnalysisResult CreateResult() => new()
|
||||
{
|
||||
Findings =
|
||||
[
|
||||
new()
|
||||
{
|
||||
Summary = "Experienced team",
|
||||
Explanation = "The documents describe long employee tenure.",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user