mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-18 00:38:00 +00:00
Added the visual briefing assistant (#893)
Build and Release / Determine run mode (push) Has been cancelled
Build and Release / Read metadata (push) Has been cancelled
Build and Release / Sync Flatpak repo (push) Has been cancelled
Build and Release / Collect Flatpak artifacts (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Has been cancelled
Build and Release / Prepare & create release (push) Has been cancelled
Build and Release / Publish release (push) Has been cancelled
Build and Release / Determine run mode (push) Has been cancelled
Build and Release / Read metadata (push) Has been cancelled
Build and Release / Sync Flatpak repo (push) Has been cancelled
Build and Release / Collect Flatpak artifacts (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Has been cancelled
Build and Release / Prepare & create release (push) Has been cancelled
Build and Release / Publish release (push) Has been cancelled
This commit is contained in:
1 parent
df4663fff4
commit
58cc811a58
214 files changed
+18943
-353
No files matched your search
@@ -0,0 +1,223 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace AIStudio.Assistants.VisualBriefing;
|
||||
|
||||
public sealed partial class VisualBriefingStore
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines <c>ReconcileAsync</c> for the visual briefing feature.
|
||||
/// </summary>
|
||||
private async Task ReconcileAsync(Guid briefingId, CancellationToken token)
|
||||
{
|
||||
var gate = this.GetLock(briefingId);
|
||||
await gate.WaitAsync(token);
|
||||
|
||||
try
|
||||
{
|
||||
var manifest = await this.LoadWithoutInitializeAsync(briefingId, token);
|
||||
if (manifest is null)
|
||||
return;
|
||||
|
||||
Directory.CreateDirectory(this.VersionsDirectory(briefingId));
|
||||
Directory.CreateDirectory(this.TranscriptsDirectory(briefingId));
|
||||
Directory.CreateDirectory(this.EvidenceArtifactsDirectory(briefingId));
|
||||
Directory.CreateDirectory(this.PlanArtifactsDirectory(briefingId));
|
||||
Directory.CreateDirectory(this.ContentArtifactsDirectory(briefingId));
|
||||
Directory.CreateDirectory(this.PresentationArtifactsDirectory(briefingId));
|
||||
Directory.CreateDirectory(this.BuildsDirectory(briefingId));
|
||||
|
||||
var builds = await this.LoadBuildsWithoutLockAsync(briefingId, token);
|
||||
foreach (var committedBuild in builds.Where(build =>
|
||||
build.Status is VisualBriefingBuildStatus.ACTIVE &&
|
||||
build.RevisionId is not null &&
|
||||
manifest.Versions.Any(version =>
|
||||
version.RevisionId == build.RevisionId &&
|
||||
version.BuildId == build.BuildId)))
|
||||
{
|
||||
var committedVersion = manifest.Versions.Single(version =>
|
||||
version.RevisionId == committedBuild.RevisionId &&
|
||||
version.BuildId == committedBuild.BuildId);
|
||||
|
||||
foreach (var stageName in new[]
|
||||
{
|
||||
VisualBriefingBuildStage.ASSEMBLY,
|
||||
VisualBriefingBuildStage.COMMIT,
|
||||
})
|
||||
{
|
||||
var stage = committedBuild.Stages.FirstOrDefault(item => item.Stage == stageName);
|
||||
if (stage is null)
|
||||
continue;
|
||||
|
||||
stage.Status = VisualBriefingBuildStageStatus.COMPLETED;
|
||||
stage.FinishedAtUtc ??= committedVersion.CreatedAtUtc;
|
||||
stage.OutputHash = committedVersion.DocumentHash;
|
||||
stage.Failure = null;
|
||||
}
|
||||
|
||||
committedBuild.CommittedRevisionId = committedVersion.RevisionId;
|
||||
committedBuild.Status = VisualBriefingBuildStatus.COMPLETED;
|
||||
committedBuild.Failure = null;
|
||||
committedBuild.UpdatedAtUtc = DateTimeOffset.UtcNow;
|
||||
|
||||
await this.StoreBuildAtomicAsync(committedBuild, token);
|
||||
}
|
||||
|
||||
foreach (var interruptedBuild in builds.Where(build => build.Status is VisualBriefingBuildStatus.ACTIVE))
|
||||
{
|
||||
var interruptedStages = interruptedBuild.Stages.Where(stage =>
|
||||
stage.Status is VisualBriefingBuildStageStatus.RUNNING).ToArray();
|
||||
|
||||
if (interruptedStages.Length == 0)
|
||||
{
|
||||
var nextStage = interruptedBuild.Stages
|
||||
.OrderBy(stage => stage.Stage)
|
||||
.FirstOrDefault(stage => stage.Status is VisualBriefingBuildStageStatus.NOT_STARTED);
|
||||
|
||||
if (nextStage is not null)
|
||||
interruptedStages = [nextStage];
|
||||
}
|
||||
|
||||
VisualBriefingFailure? interruptedFailure = null;
|
||||
foreach (var interruptedStage in interruptedStages)
|
||||
{
|
||||
interruptedStage.Status = VisualBriefingBuildStageStatus.FAILED;
|
||||
interruptedStage.FinishedAtUtc = DateTimeOffset.UtcNow;
|
||||
interruptedFailure = new()
|
||||
{
|
||||
Code = VisualBriefingFailureCode.BUILD_INTERRUPTED,
|
||||
Stage = interruptedStage.Stage,
|
||||
UserMessage = "The interrupted visual briefing build can be resumed.",
|
||||
TechnicalDetails = "The app stopped before this stage completed.",
|
||||
};
|
||||
|
||||
interruptedStage.Failure = interruptedFailure;
|
||||
}
|
||||
|
||||
if (interruptedFailure is null)
|
||||
continue;
|
||||
|
||||
interruptedBuild.Status = VisualBriefingBuildStatus.FAILED;
|
||||
interruptedBuild.Failure = interruptedFailure;
|
||||
interruptedBuild.UpdatedAtUtc = DateTimeOffset.UtcNow;
|
||||
await this.StoreBuildAtomicAsync(interruptedBuild, token);
|
||||
}
|
||||
|
||||
var changed = manifest.Versions.RemoveAll(version =>
|
||||
!File.Exists(this.VersionPath(briefingId, version))) > 0;
|
||||
|
||||
var knownFiles = manifest.Versions.Select(version => version.FileName).ToHashSet(StringComparer.Ordinal);
|
||||
foreach (var versionPath in Directory.EnumerateFiles(this.VersionsDirectory(briefingId), "*.html"))
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
var fileName = Path.GetFileName(versionPath);
|
||||
if (knownFiles.Contains(fileName))
|
||||
continue;
|
||||
|
||||
var html = await File.ReadAllTextAsync(versionPath, token);
|
||||
if (!VisualBriefingArtifactService.TryParse(html, out var parts, out _))
|
||||
continue;
|
||||
|
||||
var hashes = ComputeSectionHashes(parts);
|
||||
var versionNumber = ParseVersionNumber(fileName);
|
||||
if (versionNumber <= 0 ||
|
||||
!string.Equals(fileName, $"{versionNumber:000000}-{parts.ExportManifest.RevisionId:D}.html", StringComparison.Ordinal) ||
|
||||
manifest.Versions.Any(version => version.RevisionId == parts.ExportManifest.RevisionId ||
|
||||
version.VersionNumber == versionNumber))
|
||||
continue;
|
||||
|
||||
var matchingBuild = builds.FirstOrDefault(build => build.RevisionId == parts.ExportManifest.RevisionId);
|
||||
var semanticallyCompatible = VisualBriefingArtifactService.TryParseForRecompile(html, out _, out _);
|
||||
manifest.Versions.Add(new()
|
||||
{
|
||||
VersionNumber = versionNumber,
|
||||
SchemaVersion = parts.ExportManifest.SchemaVersion,
|
||||
IntermediateArtifactVersion = semanticallyCompatible && matchingBuild is not null
|
||||
? VisualBriefingVersions.INTERMEDIATE_ARTIFACT
|
||||
: 0,
|
||||
EvidenceContractVersion = semanticallyCompatible ? matchingBuild?.EvidenceContractVersion ?? 0 : 0,
|
||||
PlanContractVersion = semanticallyCompatible ? matchingBuild?.PlanContractVersion ?? 0 : 0,
|
||||
ContentContractVersion = semanticallyCompatible ? matchingBuild?.ContentContractVersion ?? 0 : 0,
|
||||
DesignContractVersion = semanticallyCompatible ? matchingBuild?.DesignContractVersion ?? 0 : 0,
|
||||
RevisionId = parts.ExportManifest.RevisionId,
|
||||
ParentRevisionId = parts.ExportManifest.ParentRevisionId,
|
||||
CreatedAtUtc = parts.ExportManifest.CreatedAtUtc,
|
||||
EditMode = matchingBuild?.Mode ?? VisualBriefingEditMode.IMPORT,
|
||||
Instruction = matchingBuild?.Instruction ?? string.Empty,
|
||||
DocumentHash = parts.DocumentHash,
|
||||
Origin = "Recovered from disk",
|
||||
FileName = fileName,
|
||||
DataHash = hashes.DataHash,
|
||||
AssetHash = hashes.AssetHash,
|
||||
TemplateHash = hashes.TemplateHash,
|
||||
CssHash = hashes.CssHash,
|
||||
RuntimeHash = hashes.RuntimeHash,
|
||||
EvidenceArtifactId = semanticallyCompatible ? matchingBuild?.EvidenceArtifactId : null,
|
||||
PlanArtifactId = semanticallyCompatible ? matchingBuild?.PlanArtifactId : null,
|
||||
ContentArtifactId = semanticallyCompatible ? matchingBuild?.ContentArtifactId : null,
|
||||
PresentationArtifactId = semanticallyCompatible ? matchingBuild?.PresentationArtifactId : null,
|
||||
BuildId = matchingBuild?.BuildId,
|
||||
OperationId = matchingBuild?.OperationId,
|
||||
ModelContributions = BuildRecoveredContributions(matchingBuild),
|
||||
});
|
||||
|
||||
if (matchingBuild is not null)
|
||||
{
|
||||
matchingBuild.CommittedRevisionId = parts.ExportManifest.RevisionId;
|
||||
matchingBuild.Status = VisualBriefingBuildStatus.COMPLETED;
|
||||
matchingBuild.Failure = null;
|
||||
matchingBuild.UpdatedAtUtc = DateTimeOffset.UtcNow;
|
||||
await this.StoreBuildAtomicAsync(matchingBuild, token);
|
||||
}
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
manifest.Versions = manifest.Versions.OrderBy(version => version.VersionNumber).ToList();
|
||||
manifest.ModifiedAtUtc = DateTimeOffset.UtcNow;
|
||||
await this.StoreManifestAtomicAsync(manifest, token);
|
||||
}
|
||||
}
|
||||
catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or JsonException or InvalidDataException)
|
||||
{
|
||||
logger.LogError(
|
||||
new EventId((int)VisualBriefingLogEventId.STORE_RECOVERY, VisualBriefingLogEventId.STORE_RECOVERY.ToString()),
|
||||
exception,
|
||||
"Could not reconcile visual briefing. BriefingId={BriefingId} ExceptionType={ExceptionType}",
|
||||
briefingId,
|
||||
exception.GetType().Name);
|
||||
}
|
||||
finally
|
||||
{
|
||||
gate.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reconstructs footer model roles for an orphaned committed version.
|
||||
/// </summary>
|
||||
/// <param name="build">The matching build record.</param>
|
||||
/// <returns>The recovered contributions.</returns>
|
||||
private static List<VisualBriefingModelContribution> BuildRecoveredContributions(VisualBriefingBuildRecord? build)
|
||||
{
|
||||
if (build is null || string.IsNullOrWhiteSpace(build.Model))
|
||||
return [];
|
||||
|
||||
var model = VisualBriefingModelNames.ExportLabel(build.ProviderFamily, build.Model);
|
||||
List<VisualBriefingModelContribution> contributions = [];
|
||||
if (build.EvidenceArtifactId is not null)
|
||||
contributions.Add(new(VisualBriefingModelRole.EVIDENCE, model));
|
||||
|
||||
if (build.PlanArtifactId is not null)
|
||||
contributions.Add(new(VisualBriefingModelRole.PLAN, model));
|
||||
|
||||
if (build.ContentArtifactId is not null)
|
||||
contributions.Add(new(VisualBriefingModelRole.CONTENT, model));
|
||||
|
||||
if (build.PresentationArtifactId is not null)
|
||||
contributions.Add(new(VisualBriefingModelRole.DESIGN, model));
|
||||
|
||||
return contributions;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user