| File: OpenAIFileDownloadStream.cs | |
| Project: ..\..\..\src\Libraries\Microsoft.Extensions.AI.OpenAI\Microsoft.Extensions.AI.OpenAI.csproj (Microsoft.Extensions.AI.OpenAI) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.Shared.DiagnosticIds; #pragma warning disable S4136 // Method overloads should be grouped together - .NET Core overloads grouped in #if NET block below namespace Microsoft.Extensions.AI; /// <summary> /// A <see cref="HostedFileDownloadStream"/> implementation for OpenAI file downloads. /// </summary> [Experimental(DiagnosticIds.Experiments.AIFiles, UrlFormat = DiagnosticIds.UrlFormat)] internal sealed class OpenAIFileDownloadStream : HostedFileDownloadStream { private readonly BinaryData _data; private readonly Stream _innerStream; /// <summary> /// Initializes a new instance of the <see cref="OpenAIFileDownloadStream"/> class. /// </summary> /// <param name="data">The downloaded file data.</param> /// <param name="mediaType">The media type of the file.</param> /// <param name="fileName">The file name.</param> public OpenAIFileDownloadStream(BinaryData data, string? mediaType, string? fileName) { _data = data; _innerStream = data.ToStream(); MediaType = mediaType; FileName = fileName; } /// <inheritdoc /> public override string? MediaType { get; } /// <inheritdoc /> public override string? FileName { get; } /// <inheritdoc /> public override Task<DataContent> ToDataContentAsync(CancellationToken cancellationToken = default) { if (_innerStream.Position == 0) { return Task.FromResult(new DataContent(_data.ToMemory(), MediaType ?? "application/octet-stream") { Name = FileName, }); } return base.ToDataContentAsync(cancellationToken); } /// <inheritdoc /> public override bool CanRead => _innerStream.CanRead; /// <inheritdoc /> public override bool CanSeek => _innerStream.CanSeek; /// <inheritdoc /> public override long Length => _innerStream.Length; /// <inheritdoc /> public override long Position { get => _innerStream.Position; set => _innerStream.Position = value; } /// <inheritdoc /> public override void Flush() => _innerStream.Flush(); /// <inheritdoc /> public override Task FlushAsync(CancellationToken cancellationToken) => _innerStream.FlushAsync(cancellationToken); /// <inheritdoc /> public override int ReadByte() => _innerStream.ReadByte(); /// <inheritdoc /> public override int Read(byte[] buffer, int offset, int count) => _innerStream.Read(buffer, offset, count); /// <inheritdoc /> public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => _innerStream.ReadAsync(buffer, offset, count, cancellationToken); /// <inheritdoc /> public override long Seek(long offset, SeekOrigin origin) => _innerStream.Seek(offset, origin); /// <inheritdoc /> public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken) => _innerStream.CopyToAsync(destination, bufferSize, cancellationToken); /// <inheritdoc /> protected override void Dispose(bool disposing) { if (disposing) { _innerStream.Dispose(); } base.Dispose(disposing); } #if NET public override void CopyTo(Stream destination, int bufferSize) => _innerStream.CopyTo(destination, bufferSize); /// <inheritdoc /> public override int Read(Span<byte> buffer) => _innerStream.Read(buffer); /// <inheritdoc /> public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default) => _innerStream.ReadAsync(buffer, cancellationToken); /// <inheritdoc /> public override async ValueTask DisposeAsync() { await _innerStream.DisposeAsync().ConfigureAwait(false); await base.DisposeAsync().ConfigureAwait(false); } #endif }