目录
流式输出
示例:模拟图像扩散
流式媒体
流式音频
上一篇
Gradio.Net (https://github.com/feiyun0112/Gradio.Net)是一个开源的 .NET 库,它是 Gradio 的 .NET 移植版本,允许你为机器学习模型、API 或任何 C# 函数快速构建演示或 Web 应用程序,无需任何 JavaScript、CSS 或 Web 开发经验!
流式输出
在某些情况下,您可能希望流式传输一系列输出,而不是一次显示单个输出。例如,您可能拥有一个图像生成模型,希望展示每一步生成的图像,直到最终图像生成完毕。或者,您可能有一个聊天机器人,它逐个 token 地流式传输响应,而不是一次性返回所有内容。
在这种情况下,您可以向 Gradio 提供一个生成器函数,而不是普通函数。在 C# 中,异步生成器函数使用async、IAsyncEnumerable<T>和yield return逐步产生值。
例如,下面是一个简单的生成器,它从 0 数到给定数字:
async IAsyncEnumerable<object> MyGenerator(double x) { for (int i = 0; i < (int)x; i++) yield return i; }您可以像传递普通函数一样,将生成器函数传递给 Gradio.Net。
示例:模拟图像扩散
下面是一个(模拟的)图像生成模型,在生成最终图像前,使用gr.Interface输出若干步骤的随机噪声图像:
using Gradio.Net; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; async IAsyncEnumerable<object> FakeDiffusion(double steps) { var rng = new Random(); int numSteps = (int)steps; for (int i = 0; i < numSteps; i++) { await Task.Delay(1000); // 生成随机噪声图像 var image = new Image<Rgb24>(300, 300); for (int y = 0; y < 300; y++) for (int x = 0; x < 300; x++) image[x, y] = new Rgb24( (byte)rng.Next(256), (byte)rng.Next(256), (byte)rng.Next(256)); var ms = new MemoryStream(); image.SaveAsPng(ms); image.Dispose(); yield return ms.ToArray(); } // 最终图像:橙色 var finalImage = new Image<Rgb24>(300, 300); for (int y = 0; y < 300; y++) for (int x = 0; x < 300; x++) finalImage[x, y] = new Rgb24(255, 124, 0); var finalMs = new MemoryStream(); finalImage.SaveAsPng(finalMs); finalImage.Dispose(); yield return finalMs.ToArray(); } using var demo = gr.Interface( fn: FakeDiffusion, inputs: gr.Slider(minimum: 1, maximum: 10, value: 3, step: 1), outputs: "image"); await demo.Launch();注意:我们在迭代器中添加了
await Task.Delay(1000)以在步骤之间人为制造停顿,方便观察流式输出效果。在真实的图像生成模型中,通常不需要这样做。
流式媒体
Gradio.Net 支持从生成器函数直接流式传输音频和视频。只需:
在输出的
gr.Audio或 gr.Video组件上设置 streaming: true。编写返回
IEnumerable<object>的生成器函数,每次 yield return下一个音频/视频"块"。设置
autoplay: true,使媒体自动开始播放。
对于音频,每个"块"可以是.mp3或.wav文件路径,或byte[]音频数据。对于视频,每个"块"需要是.mp4文件或使用h.264编解码器的.ts文件。
流式音频
using Gradio.Net; async IAsyncEnumerable<object> KeepRepeating(string audioFile) { for (int i = 0; i < 10; i++) { await Task.Delay(500); yield return audioFile; } } using var demo = gr.Interface( fn: KeepRepeating, inputs: gr.Audio(sources: new List<string> { "microphone" }, type: "filepath"), outputs: gr.Audio(streaming: true, autoplay: true)); await demo.Launch();引入地址