我最近尝试了各种平台来连接步骤,我想分享一个让我兴奋的平台:光学字符识别(OCR)来检测图像中的文本,并将其附加到 Discourse 帖子中!
我的沙盒主题展示了它的工作原理:https://notes.maiki.interi.org/t/testing-ocr-calls/403
我首先在 Pipedream 上完成了这个,我将通过遵循这些步骤来解释我是如何做到的。该服务有一个用于共享工作流的 Beta 功能,以下内容共享于 https://pipedream.com/new?h=tch_3Z6fa9。
虽然这可以成为使用 Pipedream 和 Discourse 的深度指南,但我将保持细节的简洁,因为我已经离开了该平台,稍后将分享更多关于它的信息。
步骤
大致的思路是:将图像 URL 发送到 Google Cloud Vision API,然后将结果通过 ChatGPT 处理,最后将结果附加到 Discourse 帖子中。
触发器

这提供了一个用于发送数据的 webhook。在 Discourse 中,我创建了一个具有两个特定设置的 webhook:

仅在帖子事件上触发意味着我的初始主题不会触发该过程;这对我很方便,因为我可以计划使用主题作为应用外部功能(我称之为“功能性笔记”)的容器。
仅在该标签上触发意味着我可以使用标签来控制每个主题生成的 webhook;通常我只会有一个“functions”标签,以保持流程逻辑简单。
Webhook 发送包含大量信息的负载,我们将在流程稍后使用主题和帖子 ID。
基于条件的结束
这是一个检查是否包含编辑原因的步骤。如果包含,则停止工作流。
在最后一步中,我更新了帖子并包含了一个编辑原因,这个检查确保我不会一直更新帖子… 
我停止使用 Pipedream 的原因之一是我的 webhook 检查消耗了该服务的积分。我认为我不应该为有条件地处理 webhook 付费,因此我继续前进…
提取图像 URL
我决定在此测试中,每个帖子都将上传一张图片。此步骤检查“cooked”值并使用以下正则表达式提取 URL:
/https?:\/\/[^\s\"]+/
Google Cloud Vision API 调用
这是 Pipedream 上的一个自定义代码步骤。预制组件不符合我的要求,该服务还有一个代码助手,可以根据提示编写代码;由于这些 API 调用很简单,因此很容易通过这种方法生成。
它获取上一步的值({{steps.extract_by_regular_expression.$return_value[0].match}}),代码如下:
import { axios } from "@pipedream/platform";
export default defineComponent({
props: {
imageUrl: {
type: "string",
label: "Image URL",
description: "URL of the image to be processed by Google Vision API",
},
apiKey: {
type: "string",
label: "API Key",
description: "Your Google Cloud API Key",
secret: true,
},
},
async run() {
const url = `https://vision.googleapis.com/v1/images:annotate?key=${this.apiKey}`;
const body = {
requests: [
{
image: {
source: {
imageUri: this.imageUrl,
},
},
features: [
{
type: "TEXT_DETECTION",
},
],
},
],
};
const config = {
method: "POST",
url,
data: body,
};
const response = await axios(this, config);
return response;
},
});
ChatGPT 进行编辑
获取上一步的输出({{steps.google_cloud.$return_value.responses[0].fullTextAnnotation.text}})并将其作为用户消息传递。对于系统消息,我有:
你正在阅读 Vision API 检测图像中文本的输出。请审阅消息并进行编辑以提高清晰度。仅返回编辑后的文本,不带任何评论。
附加到 Discourse 帖子
这是另一个自定义代码部分,因为 Pipedream 中预制的Discourse 操作仅涵盖了少数场景(创建主题或帖子),而我想将文本附加到帖子中。
首先,这是代码:
import { axios } from "@pipedream/platform";
export default defineComponent({
props: {
discourse: {
type: "app",
app: "discourse",
},
postId: {
type: "string",
label: "Post ID",
description: "The ID of the post to append text to",
},
text: {
type: "string",
label: "Text",
description: "The text to append to the post",
},
editReason: {
type: "string",
label: "Edit Reason",
description: "The reason for editing the post",
optional: true,
},
},
async run({ steps, $ }) {
const url = `https://${this.discourse.$auth.domain}/posts/${this.postId}.json`;
const response = await axios($, {
method: "GET",
url: url,
headers: {
"Api-Username": `${this.discourse.$auth.api_username}`,
"Api-Key": `${this.discourse.$auth.api_key}`,
},
});
const updatedText = `${response.raw} ${this.text}`;
return await axios($, {
method: "PUT",
url: url,
headers: {
"Api-Username": `${this.discourse.$auth.api_username}`,
"Api-Key": `${this.discourse.$auth.api_key}`,
},
data: {
post: {
raw: updatedText,
edit_reason: this.editReason,
},
},
});
},
});
这些步骤的属性填写如下:
帖子 ID
从原始负载中获取帖子 ID:{{steps.trigger.event.body.post.id}}
这用于直接编辑该帖子。
文本
---
<blockquote>
{{steps.chat.$return_value.generated_message.content}}
</blockquote>
[details="Detected text"]
{{steps.google_cloud.$return_value.responses[0].textAnnotations[0].description}}
[/details]
基本上,我想在每个图像下方添加一个水平分隔线,其中包含一个编辑过的文本的块引用,以及用于检查原始输出的详细信息。
由于每个帖子只包含一张图片,这很容易实现。我想知道如何一次处理多张图片?
编辑原因
OCR 文本检测
这被添加为帖子更新的编辑原因,这将防止由于开头的步骤而导致帖子更新循环。

我发现始终包含编辑原因非常有帮助,尤其是在处理外部服务时。
就是这样!正如你从我的沙盒中看到的,效果相当不错!
我即将进行一次旅行,我计划对 OpenAI 编辑进行微调,使其在需要时也能翻译成英文,这是我将添加到此工作流系统提示中的一个选项。