PlotDirector/PlotLine/Services/StoryIntelligenceSceneStructuredOutputSchema.cs

211 lines
9.4 KiB
C#

using PlotLine.Models;
namespace PlotLine.Services;
public static class StoryIntelligenceSceneStructuredOutputSchema
{
public const string ContractName = "scene_intelligence_v1";
public static StoryIntelligenceResponseContract Contract { get; } = new()
{
Name = ContractName,
Strict = true,
Schema = BuildSchema()
};
private static Dictionary<string, object> BuildSchema()
{
var sceneReference = Obj(Props(
("projectId", NullableInteger()),
("bookId", NullableInteger()),
("chapterId", NullableInteger()),
("sceneId", NullableInteger()),
("chapterNumber", NullableNumber()),
("sceneNumber", NullableNumber()),
("sourceLabel", Str())));
var purpose = Obj(Props(("observedFunction", Str()), ("confidence", Confidence())));
var pointOfView = Obj(Props(
("characterName", NullableString()),
("narrativeMode", NullableString()),
("confidence", Confidence()),
("evidence", NullableString())));
var setting = Obj(Props(
("timeOfDay", NullableString()),
("dateOrTimeReference", NullableString()),
("locationName", NullableString()),
("locationType", Enum("named", "generic", "unclear")),
("genericRoomType", NullableString()),
("parentLocationHint", NullableString()),
("confidence", Confidence())));
var characters = Arr(Obj(Props(
("name", Str()),
("roleInScene", Enum("present", "pointOfView", "speaker", "mentioned", "unclear")),
("mentionedOnly", Bool()),
("aliases", Arr(Str())),
("actions", Arr(Str())),
("confidence", Confidence()),
("notes", NullableString()))));
var characterAppearance = Arr(Obj(Props(
("canonicalName", Str()),
("aliases", Arr(Str())),
("title", NullableString()),
("presentation", NullableString()),
("explicitAge", NullableString()),
("inferredAgeBand", NullableString()),
("hairColour", NullableString()),
("hairLength", NullableString()),
("hairStyle", NullableString()),
("eyeColour", NullableString()),
("facialHair", NullableString()),
("glasses", NullableString()),
("height", NullableString()),
("build", NullableString()),
("distinctiveFeatures", Arr(Str())),
("clothing", NullableString()),
("roleOrOccupation", NullableString()),
("relationshipAgeEvidence", NullableString()),
("pronounEvidence", NullableString()),
("evidence", Str()),
("confidence", Confidence()),
("evidenceKind", Enum("explicit", "inferred")))));
var locations = Arr(Obj(Props(
("name", Str()),
("locationType", Enum("named", "generic", "unclear")),
("genericRoomType", NullableString()),
("parentLocationHint", NullableString()),
("presentInScene", Bool()),
("mentionedOnly", Bool()),
("confidence", Confidence()),
("notes", NullableString()))));
var assets = Arr(Obj(Props(
("name", Str()),
("assetType", NullableString()),
("status", NullableString()),
("ownerOrHolder", NullableString()),
("mentionedOnly", Bool()),
("confidence", Confidence()),
("notes", NullableString()))));
var relationships = Arr(Obj(Props(
("characterA", Str()),
("characterB", Str()),
("relationshipSignal", Enum("trust", "mistrust", "affection", "fear", "authority", "secrecy", "conflict", "dependence", "protection", "rivalry", "obligation")),
("evidence", Str()),
("confidence", Confidence()))));
var knowledgeChanges = Arr(Obj(Props(
("recipientCharacter", Str()),
("knowledgeItem", Str()),
("changeType", Enum("Learns", "Realises", "IsTold", "Discovers", "Confirms", "Suspects", "Misunderstands")),
("sourceCharacter", NullableString()),
("sourceType", NullableString()),
("evidence", Str()),
("confidence", Confidence()))));
var timelineClues = Arr(Obj(Props(
("clue", Str()),
("relativeOrder", NullableString()),
("absoluteDate", NullableString()),
("evidence", Str()),
("confidence", Confidence()))));
var narrativeArcs = Arr(Obj(Props(
("title", Str()),
("description", Str()),
("arcType", Str()),
("scale", Enum("major", "secondary", "thread")),
("changeType", Enum("Introduced", "Developed", "Complicated", "Revealed", "Escalated", "Resolved", "Reopened", "Mentioned")),
("significance", Enum("major", "moderate", "minor")),
("continuityKey", Str()),
("parentArcTitle", NullableString()),
("matchingExistingPlotLineId", NullableInteger()),
("matchingExistingThreadId", NullableInteger()),
("evidence", Str()),
("confidence", Confidence()))));
var questionsRaised = Arr(Obj(Props(("question", Str()), ("scope", Str()), ("evidence", Str()), ("confidence", Confidence()))));
var questionsAnswered = Arr(Obj(Props(("question", Str()), ("answer", Str()), ("evidence", Str()), ("confidence", Confidence()))));
var observations = Arr(Obj(Props(
("observationType", Enum("CharacterAction", "CharacterKnowledge", "CharacterLocation", "RelationshipSignal", "AssetInteraction", "LocationSignal", "TimelineSignal", "QuestionSignal")),
("subjectEntityType", Enum("Character", "Location", "Asset", "Knowledge", "Relationship", "Timeline", "Scene", "Unknown")),
("subjectName", Str()),
("objectEntityType", NullableEnum("Character", "Location", "Asset", "Knowledge", "Relationship", "Timeline", "Scene", "Unknown")),
("objectName", NullableString()),
("predicate", Str()),
("description", Str()),
("evidence", Str()),
("confidence", Confidence()))));
var metricValues = Arr(Obj(Props(
("key", Str("Configured metric key from sceneContext.configuredMetrics.")),
("score", Integer()),
("confidence", Confidence()))));
var sourceLimits = Obj(Props(("containsAmbiguity", Bool()), ("ambiguityNotes", Arr(Str()))));
return Obj(Props(
("schemaVersion", Str("Scene Intelligence schema version. Use 1.0.")),
("sceneReference", sceneReference),
("scenePurpose", purpose),
("pointOfView", pointOfView),
("setting", setting),
("characters", characters),
("characterAppearance", characterAppearance),
("locations", locations),
("assets", assets),
("relationships", relationships),
("knowledgeChanges", knowledgeChanges),
("timelineClues", timelineClues),
("narrativeArcs", narrativeArcs),
("questionsRaised", questionsRaised),
("questionsAnswered", questionsAnswered),
("observations", observations),
("metricValues", metricValues),
("sourceLimits", sourceLimits)));
}
private static Dictionary<string, object> Obj(Dictionary<string, object> properties)
=> new()
{
["type"] = "object",
["properties"] = properties,
["required"] = properties.Keys.ToArray(),
["additionalProperties"] = false
};
private static Dictionary<string, object> Arr(object items)
=> new() { ["type"] = "array", ["items"] = items };
private static Dictionary<string, object> Str(string? description = null)
{
var value = new Dictionary<string, object> { ["type"] = "string" };
if (!string.IsNullOrWhiteSpace(description))
{
value["description"] = description;
}
return value;
}
private static Dictionary<string, object> NullableString()
=> new() { ["type"] = new[] { "string", "null" } };
private static Dictionary<string, object> Integer()
=> new() { ["type"] = "integer" };
private static Dictionary<string, object> NullableInteger()
=> new() { ["type"] = new[] { "integer", "null" } };
private static Dictionary<string, object> NullableNumber()
=> new() { ["type"] = new[] { "number", "null" } };
private static Dictionary<string, object> Bool()
=> new() { ["type"] = "boolean" };
private static Dictionary<string, object> Confidence()
=> new() { ["type"] = "number", ["minimum"] = 0, ["maximum"] = 1 };
private static Dictionary<string, object> Enum(params string[] values)
=> new() { ["type"] = "string", ["enum"] = values };
private static Dictionary<string, object> NullableEnum(params string[] values)
=> new() { ["type"] = new[] { "string", "null" }, ["enum"] = values.Cast<string?>().Append(null).ToArray() };
private static Dictionary<string, object> Props(params (string Name, object Schema)[] properties)
=> properties.ToDictionary(property => property.Name, property => property.Schema, StringComparer.Ordinal);
}