65.9K
CodeProject 正在变化。 阅读更多。
Home

创建文件上传机器人

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2022年2月14日

CPOL

4分钟阅读

viewsIcon

5147

如何创建一个 Java Spring Boot Web 应用程序,该应用程序复制 GitHub 上“Teams 文件上传”示例应用程序的功能

聊天机器人提供了一个方便的文件上传平台。像 Microsoft Teams 这样的聊天平台已经提供了附加文件的熟悉界面,并负责托管任何消息附件。这使我们不必编写处理文件上传的平凡但又棘手的逻辑。

在这篇文章中,我们将创建一个机器人,用于下载和处理聊天消息中的文件附件。

必备组件

要阅读本文,您需要 Java 11 JDKApache MavenNode.js 和 npm、用于部署最终应用程序的 Azure 订阅以及 Azure CLI

我还使用了一个脚手架工具 Yeoman 来简化设置。使用以下命令安装它

npm install -g yo

聊天机器人模板由generator-botbuilder-java包提供,您需要使用此命令安装它

npm install -g generator-botbuilder-java

现在,您已经拥有了创建示例聊天机器人应用程序所需的一切。

示例源代码

您可以通过查看此项目的 GitHub 页面 上的源代码来跟进。

构建基础应用程序

有关构建和更新基础应用程序的过程,请参阅本系列中的上一篇文章。按照“创建示例应用程序”和“更新示例应用程序”标题下的说明,使用 Yeoman 创建一个 Spring Boot 项目。

添加新依赖项

除了上一篇文章中提到的更新的依赖项外,您还需要添加 Maven 依赖项来支持您的文件上传机器人。

将以下依赖项添加到 pom.xml 文件中

<dependencies>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.11.0</version>
    </dependency>
    …
</dependencies>

构建上传机器人

您的机器人定义在 UploadBot 类中,并扩展了 ActivityHandler

public class UploadBot extends ActivityHandler {

onMembersAdded 方法向任何新聊天成员显示一条消息,告知他们机器人将从消息附件中下载文件

  @Override
  protected CompletableFuture<Void> onMembersAdded(
      final List<ChannelAccount> membersAdded,
      final TurnContext turnContext
  ) {
    return membersAdded.stream()
        .filter(
            member -> !StringUtils
                .equals(member.getId(), turnContext.getActivity().getRecipient().getId())
        ).map(channel -> turnContext.sendActivity(
            MessageFactory.text
            ("Welcome! Post a message with an attachment and I'll download it!")))
        .collect(CompletableFutures.toFutureList()).thenApply(resourceResponses -> null);
  }

onMessageActivity 方法会检查任何新消息,以确定它们是否具有附件

  @Override
  protected CompletableFuture<Void> onMessageActivity(final TurnContext turnContext) {
    if (messageWithDownload(turnContext.getActivity())) {
      final Attachment attachment = turnContext.getActivity().getAttachments().get(0);

如果找到附件,文件将被下载到本地临时位置

      return downloadAttachment(attachment)

如果文件下载出现任何问题,将向聊天发送一条消息

          .thenCompose(result -> !result.result()
              ? turnContext.sendActivityBlind(
              MessageFactory.text("Failed to download the attachment"))

如果附件已成功下载,则对其进行检查,并将文件长度和类型发送到聊天

              : turnContext.sendActivityBlind(
                  MessageFactory.text(
                      "Downloaded file " + attachment.getName() + ". It was "
                          + getFileSize(result.getRight())
                          + " bytes long and appears to be of type "
                          + getFileType(result.getRight())))
          );
    }

如果没有找到附件,机器人会在聊天中发送一条提醒,告知用户它将下载任何附件

    return turnContext.sendActivity(
        MessageFactory.text("Post a message with an attachment and I'll download it!")
    ).thenApply(sendResult -> null);
  }

要确定消息是否具有附件,messageWithDownload 方法会检查附件集合并验证第一个附件的内容类型

  private boolean messageWithDownload(final Activity activity) {
    return activity.getAttachments() != null
        && activity.getAttachments().size() > 0
        && StringUtils.equalsIgnoreCase(
        activity.getAttachments().get(0).getContentType(),
        FileDownloadInfo.CONTENT_TYPE);
  }

下载附件类似于从 HTTP 服务器下载任何文件。downloadAttachment 方法将附件下载到临时位置

  private CompletableFuture<ResultPair<String>> downloadAttachment(final Attachment attachment) {

从 lambda 方法内部访问的任何共享变量都必须是 final 或 effectively final,这意味着其值一旦设置就不会改变。

因此,您的文件下载结果被捕获在 ResultPair 中,该对象被包装在一个 final AtomicReference 中。这允许您从接下来创建的 lambda 方法中返回文件下载的结果

    final AtomicReference<ResultPair<String>> result = new AtomicReference<>();

该应用程序创建一个临时文件,然后使用 Apache Commons 库将附件下载到该文件中

    return CompletableFuture.runAsync(() -> {
          try {
            final FileDownloadInfo fileDownload = Serialization
                .getAs(attachment.getContent(), FileDownloadInfo.class);
            final File filePath = Files.createTempFile(
                FilenameUtils.getBaseName(attachment.getName()),
                "." + FilenameUtils.getExtension(attachment.getName())).toFile();

            FileUtils.copyURLToFile(
                new URL(fileDownload.getDownloadUrl()),
                filePath,
                30000,
                30000);

如果一切顺利,您将通过设置 AtomicReference 包装的值来返回 true 和临时文件的路径

            result.set(new ResultPair<>(true, filePath.getAbsolutePath()));
          } catch (Throwable t) {

如果发生错误,您将返回 false 和错误消息

            result.set(new ResultPair<>(false, t.getLocalizedMessage()));
          }
        })

然后 CompletableFuture 返回包装的 ResultPair

        .thenApply(aVoid -> result.get());
  }

为了证明机器人已成功下载附件,getFileSize 方法返回文件的大小

  private long getFileSize(final String path) {
    try {
      return Files.size(Paths.get(path));
    } catch (IOException e) {
      return -1;
    }
  }

您还可以使用 getFileType 方法检查文件的类型

  private String getFileType(final String path) {
    try {
      final String type = Files.probeContentType(Paths.get(path));
      return type == null ? "unknown" : type;
    } catch (IOException e) {
      return "unknown";
    }
  }
}

测试机器人

有关将招待机器人部署并集成到 Teams 中的说明,请参阅本系列第一篇文章中的说明的“部署机器人”和“链接到 Teams”部分。

然后,发送一条带有附件的消息。机器人将检测到附件,下载它,并返回文件大小和类型

Title: Inserting image...

结论

使用聊天机器人处理文件非常简单,只需要能够从消息中的常规附件下载 HTTP 文件。

在这篇文章中,您创建了一个简单的聊天机器人,该机器人下载了任何消息附件,并返回文件大小以表明它已成功下载附件。

这个例子很容易扩展,可以添加您的团队可能需要的任何附加逻辑,允许用户通过熟悉的 Teams 聊天界面上传文件。它可以作为文件转换等工具的基础,并支持工作流或应用程序部署。只需从 GitHub 克隆源代码,并将您自己的自定义逻辑添加到 UploadBot 类中,即可构建适合您需求的机器人。

要了解有关为 Microsoft Teams 构建自己的机器人的更多信息,请参阅 使用 Azure Bot Framework Composer 为 Microsoft Teams 构建出色的机器人

© . All rights reserved.