feat: Cloudflare R2 对象存储支持

This commit is contained in:
Hk-Gosuto 2023-09-16 19:01:35 +08:00
parent 6d8150a1b0
commit 2947274ce6
7 changed files with 1156 additions and 21 deletions

View File

@ -0,0 +1,36 @@
import { NextRequest, NextResponse } from "next/server";
import { auth } from "../../auth";
import S3FileStorage from "../../../utils/r2_file_storage";
async function handle(
req: NextRequest,
{ params }: { params: { path: string[] } },
) {
if (req.method === "OPTIONS") {
return NextResponse.json({ body: "OK" }, { status: 200 });
}
const authResult = auth(req);
if (authResult.error) {
return NextResponse.json(authResult, {
status: 401,
});
}
try {
var file = await S3FileStorage.get(params.path[0]);
return new Response(file?.transformToWebStream(), {
headers: {
"Content-Type": "image/png",
},
});
} catch (e) {
return new Response("not found", {
status: 404,
});
}
}
export const GET = handle;
export const runtime = "edge";

View File

@ -1,9 +1,6 @@
import * as fs from "fs";
import * as path from "path";
import axios from "axios";
import { Tool } from "langchain/tools";
import OpenAI from "openai";
import S3FileStorage from "../../utils/r2_file_storage";
export class DallEAPIWrapper extends Tool {
name = "dalle_image_generator";
@ -22,20 +19,10 @@ export class DallEAPIWrapper extends Tool {
}
async saveImageFromUrl(url: string) {
const response = await axios.get(url, { responseType: "arraybuffer" });
const uploadsDir = "public/uploads";
console.log("[fileUpload]", { uploadsDir });
if (!fs.existsSync(uploadsDir)) {
fs.mkdirSync(uploadsDir, { recursive: true });
}
const filename = `${Date.now()}.png`;
const filePath = path.join(uploadsDir, filename);
fs.writeFileSync(filePath, Buffer.from(response.data, "binary"));
return `uploads/${filename}`;
const response = await fetch(url);
const content = await response.arrayBuffer();
const buffer = Buffer.from(content);
return await S3FileStorage.put(`${Date.now()}.png`, buffer);
}
/** @ignore */
@ -61,5 +48,5 @@ export class DallEAPIWrapper extends Tool {
description = `openai's dall-e image generator.
input must be a english prompt.
output will be the image link url.
use markdown to display images.`;
use markdown to display images. like: ![img](/api/file/xxx.png)`;
}

View File

@ -42,7 +42,8 @@ export const CN_PLUGINS: BuiltinPlugin[] = [
name: "DALL·E",
toolName: "dalle_image_generator",
lang: "cn",
description: "DALL·E 可以根据自然语言的描述创建逼真的图像和艺术。",
description:
"DALL·E 可以根据自然语言的描述创建逼真的图像和艺术。使用本插件需要配置 Cloudflare R2 对象存储服务。",
builtin: true,
createdAt: 1694703673000,
enable: false,

View File

@ -45,7 +45,7 @@ export const EN_PLUGINS: BuiltinPlugin[] = [
toolName: "dalle_image_generator",
lang: "en",
description:
"DALL·E 2 is an AI system that can create realistic images and art from a description in natural language.",
"DALL·E 2 is an AI system that can create realistic images and art from a description in natural language. Using this plugin requires configuring Cloudflare R2 object storage service.",
builtin: true,
createdAt: 1694703673000,
enable: false,

View File

@ -0,0 +1,61 @@
import {
S3Client,
ListBucketsCommand,
ListObjectsV2Command,
GetObjectCommand,
PutObjectCommand,
} from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
const R2_ACCOUNT_ID = process.env.R2_ACCOUNT_ID;
const R2_ACCESS_KEY_ID = process.env.R2_ACCESS_KEY_ID;
const R2_SECRET_ACCESS_KEY = process.env.R2_SECRET_ACCESS_KEY;
const R2_BUCKET = process.env.R2_BUCKET;
const getR2Client = () => {
return new S3Client({
region: "auto",
endpoint: `https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
credentials: {
accessKeyId: R2_ACCESS_KEY_ID!,
secretAccessKey: R2_SECRET_ACCESS_KEY!,
},
});
};
export default class S3FileStorage {
static async get(fileName: string) {
const file = await getR2Client().send(
new GetObjectCommand({
Bucket: R2_BUCKET,
Key: fileName,
}),
);
if (!file) {
throw new Error("not found.");
}
return file.Body;
}
static async put(fileName: string, data: Buffer) {
const signedUrl = await getSignedUrl(
getR2Client(),
new PutObjectCommand({
Bucket: R2_BUCKET,
Key: fileName,
}),
{ expiresIn: 60 },
);
console.log(signedUrl);
await fetch(signedUrl, {
method: "PUT",
body: data,
});
return `/api/file/${fileName}`;
}
}

View File

@ -16,6 +16,8 @@
"proxy-dev": "sh ./scripts/init-proxy.sh && proxychains -f ./scripts/proxychains.conf yarn dev"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.414.0",
"@aws-sdk/s3-request-presigner": "^3.414.0",
"@fortaine/fetch-event-source": "^3.0.6",
"@hello-pangea/dnd": "^16.3.0",
"@svgr/webpack": "^6.5.1",

1048
yarn.lock

File diff suppressed because it is too large Load Diff