You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Bot Framework表单中如何实现用户上传图片附件?

Bot Framework表单实现图片上传的解决方案

当然可以实现Bot Framework表单中的图片上传功能!你遇到的问题主要是两个原因:一是byte类型仅能存储单个字节,完全无法容纳完整的图片二进制数据;二是默认的表单提示逻辑不支持触发文件上传的交互。下面是具体的实现步骤:

1. 修正表单字段类型

首先把图片字段的类型从byte改为byte[],这样才能存储完整的图片二进制数据:

[Serializable]
public class VehicleForm
{
    [Prompt("When did this happen")]
    public DateTime LossDate { get; set; }

    // 改为byte[]存储图片二进制数据
    public byte[] Picture { get; set; }
}

2. 用自适应卡片实现文件上传交互

Bot Framework的默认表单输入不支持文件上传,我们需要自定义表单的渲染逻辑,通过**自适应卡片(Adaptive Cards)**的Input.File组件来提供上传入口。

你可以重写表单的OnRenderAsync方法,当渲染到图片字段时,返回包含文件上传组件的自适应卡片:

protected override async Task<Activity> OnRenderAsync(FormContext formContext, object state, CancellationToken cancellationToken)
{
    var baseActivity = await base.OnRenderAsync(formContext, state, cancellationToken);

    // 判断当前是否渲染图片字段
    if (formContext.LastField?.Name == nameof(VehicleForm.Picture))
    {
        var uploadCard = new AdaptiveCard(new AdaptiveSchemaVersion(1, 0))
        {
            Body = new List<AdaptiveElement>
            {
                new AdaptiveTextBlock { Text = "请上传证明图片", Size = AdaptiveTextSize.Medium },
                new AdaptiveFileInput { Id = "pictureFile", AllowMultipleFiles = false }
            },
            Actions = new List<AdaptiveAction>
            {
                new AdaptiveSubmitAction { Title = "确认上传", Data = new { FormAction = "UploadPicture" } }
            }
        };

        // 替换原活动内容为自适应卡片
        baseActivity.Attachments = new List<Attachment>
        {
            new Attachment { ContentType = AdaptiveCard.ContentType, Content = uploadCard }
        };
    }

    return baseActivity;
}

3. 处理用户上传的文件数据

当用户提交图片后,需要在Bot的消息处理逻辑中解析上传的文件内容,将其转换为byte[]后赋值给表单的Picture字段。注意不同聊天渠道(如Teams、Web Chat)的文件获取方式略有差异,这里以通用逻辑为例:

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    var formState = await _formAccessor.GetAsync(turnContext, () => new VehicleForm(), cancellationToken);
    var formContext = new FormContext<VehicleForm>(turnContext, formState, _formOptions);

    // 判断是否是图片上传提交
    if (turnContext.Activity.Value != null && turnContext.Activity.Value.ToString().Contains("UploadPicture"))
    {
        // 获取上传的文件附件
        var fileAttachment = turnContext.Activity.Attachments?.FirstOrDefault(a => a.ContentType.StartsWith("image/"));
        if (fileAttachment != null)
        {
            // 从附件中读取二进制数据
            using var httpClient = new HttpClient();
            var fileStream = await httpClient.GetStreamAsync(fileAttachment.ContentUrl);
            using var memoryStream = new MemoryStream();
            await fileStream.CopyToAsync(memoryStream);
            formState.Picture = memoryStream.ToArray();

            // 手动推进表单到下一个步骤
            await formContext.ContinueAsync(cancellationToken);
        }
    }
    else
    {
        // 处理普通表单输入
        await formContext.ContinueAsync(cancellationToken);
    }

    await _formAccessor.SetAsync(turnContext, formState, cancellationToken);
}

注意事项

  • 不同渠道(如Teams)的文件ContentUrl可能需要权限验证,你可能需要使用渠道特定的API来获取文件内容;
  • 可以根据需求限制上传文件的类型(如仅允许jpg/png)和大小,避免过大文件导致性能问题。

内容的提问来源于stack exchange,提问作者Oluwatosin Samuel Babalola

火山引擎 最新活动