using System.Collections.Concurrent; using System.Text; namespace AIStudio.Tools; public static class ContentStreamSseHandler { private static readonly ConcurrentDictionary> CHUNKED_IMAGES = new(); private static readonly ConcurrentDictionary CURRENT_SLIDE_NUMBERS = new(); public static string? ProcessEvent(ContentStreamSseEvent? sseEvent, bool extractImages = true) { switch (sseEvent) { case { Content: not null, Metadata: not null }: switch (sseEvent.Metadata) { case ContentStreamTextMetadata: return sseEvent.Content; case ContentStreamPdfMetadata pdfMetadata: var pageNumber = pdfMetadata.Pdf?.PageNumber ?? 0; return $""" # Page {pageNumber} {sseEvent.Content} """; case ContentStreamSpreadsheetMetadata spreadsheetMetadata: var sheetName = spreadsheetMetadata.Spreadsheet?.SheetName; var rowNumber = spreadsheetMetadata.Spreadsheet?.RowNumber; var spreadSheetResult = new StringBuilder(); if (rowNumber == 0) { spreadSheetResult.AppendLine(); spreadSheetResult.AppendLine($"# {sheetName}"); } spreadSheetResult.Append(sseEvent.Content); return spreadSheetResult.ToString(); case ContentStreamDocumentMetadata: case ContentStreamImageMetadata: return sseEvent.Content; case ContentStreamPresentationMetadata presentationMetadata: var slideNumber = presentationMetadata.Presentation?.SlideNumber ?? 0; var image = presentationMetadata.Presentation?.Image ?? null; var presentationResult = new StringBuilder(); var streamId = sseEvent.StreamId; CURRENT_SLIDE_NUMBERS.TryGetValue(streamId!, out var currentSlideNumber); if (slideNumber != currentSlideNumber) { presentationResult.AppendLine(); presentationResult.AppendLine($"# Slide {slideNumber}"); } if(!string.IsNullOrWhiteSpace(sseEvent.Content)) presentationResult.AppendLine(sseEvent.Content); if (extractImages && image is not null) { var imageId = $"{streamId}-{image.Id!}"; var isEnd = ProcessImageSegment(imageId, image); if (isEnd && extractImages) presentationResult.AppendLine(BuildImage(imageId)); } CURRENT_SLIDE_NUMBERS[streamId!] = slideNumber; return presentationResult.Length is 0 ? null : presentationResult.ToString(); default: return sseEvent.Content; } case { Content: not null, Metadata: null }: return sseEvent.Content; default: return null; } } private static bool ProcessImageSegment(string imageId, ContentStreamPptxImageData contentStreamPptxImageData) { if (string.IsNullOrWhiteSpace(contentStreamPptxImageData.Id) || string.IsNullOrWhiteSpace(imageId)) return false; var segment = contentStreamPptxImageData.Segment ?? 0; var content = contentStreamPptxImageData.Content ?? string.Empty; var isEnd = contentStreamPptxImageData.IsEnd; var imageSegment = new ContentStreamPptxImageData { Id = imageId, Content = content, Segment = segment, IsEnd = isEnd, }; CHUNKED_IMAGES.AddOrUpdate( imageId, _ => [imageSegment], (_, existingList) => { existingList.Add(imageSegment); return existingList; } ); return isEnd; } private static string BuildImage(string id) { if (!CHUNKED_IMAGES.TryGetValue(id, out var imageSegments)) return string.Empty; var sortedSegments = imageSegments .OrderBy(item => item.Segment) .ToList(); var base64Image = string.Join(string.Empty, sortedSegments .Where(item => item.Content != null) .Select(item => item.Content)); CHUNKED_IMAGES.Remove(id, out _); return base64Image; } }