mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-05-26 07:30:18 +09:00
feat: support custom s3 service
This commit is contained in:
parent
eb7711f832
commit
b84da5e120
22
README.md
22
README.md
@ -37,6 +37,8 @@
|
|||||||
|
|
||||||
- 除插件工具外,与原项目保持一致 [ChatGPT-Next-Web 主要功能](https://github.com/Yidadaa/ChatGPT-Next-Web#主要功能)
|
- 除插件工具外,与原项目保持一致 [ChatGPT-Next-Web 主要功能](https://github.com/Yidadaa/ChatGPT-Next-Web#主要功能)
|
||||||
- 支持 GPT-4V(视觉) 模型
|
- 支持 GPT-4V(视觉) 模型
|
||||||
|
- 需要配置对象存储服务,请参考 [对象存储服务配置指南](./docs/s3-oss.md) 配置
|
||||||
|
|
||||||
- 基于 [LangChain](https://github.com/hwchase17/langchainjs) 实现的插件功能,目前支持以下插件,未来会添加更多
|
- 基于 [LangChain](https://github.com/hwchase17/langchainjs) 实现的插件功能,目前支持以下插件,未来会添加更多
|
||||||
- 搜索
|
- 搜索
|
||||||
- [SerpAPI](https://js.langchain.com/docs/api/tools/classes/SerpAPI)
|
- [SerpAPI](https://js.langchain.com/docs/api/tools/classes/SerpAPI)
|
||||||
@ -51,11 +53,11 @@
|
|||||||
- 其它
|
- 其它
|
||||||
- [Wiki](https://js.langchain.com/docs/api/tools/classes/WikipediaQueryRun)
|
- [Wiki](https://js.langchain.com/docs/api/tools/classes/WikipediaQueryRun)
|
||||||
- DALL-E 3
|
- DALL-E 3
|
||||||
- DALL-E 3 插件需要配置 R2 存储,请参考 [Cloudflare R2 服务配置指南](./docs/cloudflare-r2-cn.md) 配置
|
- DALL-E 3 插件需要配置对象存储服务,请参考 [对象存储服务配置指南](./docs/s3-oss.md) 配置
|
||||||
- StableDiffusion
|
- StableDiffusion
|
||||||
- 本插件目前为测试版本,后续可能会有较大的变更,请谨慎使用
|
- 本插件目前为测试版本,后续可能会有较大的变更,请谨慎使用
|
||||||
- 使用本插件需要一定的专业知识,Stable Diffusion 本身的相关问题不在本项目的解答范围内,如果您确定要使用本插件请参考 [Stable Diffusion 插件配置指南](./docs/stable-diffusion-plugin-cn.md) 文档进行配置
|
- 使用本插件需要一定的专业知识,Stable Diffusion 本身的相关问题不在本项目的解答范围内,如果您确定要使用本插件请参考 [Stable Diffusion 插件配置指南](./docs/stable-diffusion-plugin-cn.md) 文档进行配置
|
||||||
- StableDiffusion 插件需要配置 R2 存储,请参考 [Cloudflare R2 服务配置指南](./docs/cloudflare-r2-cn.md) 配置
|
- StableDiffusion 插件需要配置对象存储服务,请参考 [对象存储服务配置指南](./docs/s3-oss.md) 配置
|
||||||
- Arxiv
|
- Arxiv
|
||||||
|
|
||||||
## 开发计划
|
## 开发计划
|
||||||
@ -181,22 +183,6 @@ OpenAI 接口代理 URL,如果你手动配置了 openai 接口代理,请填
|
|||||||
|
|
||||||
如果你不想让用户查询余额,将此环境变量设置为 1 即可。
|
如果你不想让用户查询余额,将此环境变量设置为 1 即可。
|
||||||
|
|
||||||
### `R2_ACCOUNT_ID` (可选)
|
|
||||||
|
|
||||||
Cloudflare R2 帐户 ID,使用 `DALL-E` 插件时需要配置。
|
|
||||||
|
|
||||||
### `R2_ACCESS_KEY_ID` (可选)
|
|
||||||
|
|
||||||
Cloudflare R2 访问密钥 ID,使用 `DALL-E` 插件时需要配置。
|
|
||||||
|
|
||||||
### `R2_SECRET_ACCESS_KEY` (可选)
|
|
||||||
|
|
||||||
Cloudflare R2 机密访问密钥,使用 `DALL-E` 插件时需要配置。
|
|
||||||
|
|
||||||
### `R2_BUCKET` (可选)
|
|
||||||
|
|
||||||
Cloudflare R2 Bucket 名称,使用 `DALL-E` 插件时需要配置。
|
|
||||||
|
|
||||||
## 部署
|
## 部署
|
||||||
|
|
||||||
### 容器部署 (推荐)
|
### 容器部署 (推荐)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import { auth } from "../../auth";
|
import S3FileStorage from "../../../utils/s3_file_storage";
|
||||||
import S3FileStorage from "../../../utils/r2_file_storage";
|
|
||||||
|
|
||||||
async function handle(
|
async function handle(
|
||||||
req: NextRequest,
|
req: NextRequest,
|
||||||
@ -10,13 +9,6 @@ async function handle(
|
|||||||
return NextResponse.json({ body: "OK" }, { status: 200 });
|
return NextResponse.json({ body: "OK" }, { status: 200 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// const authResult = auth(req);
|
|
||||||
// if (authResult.error) {
|
|
||||||
// return NextResponse.json(authResult, {
|
|
||||||
// status: 401,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var file = await S3FileStorage.get(params.path[0]);
|
var file = await S3FileStorage.get(params.path[0]);
|
||||||
return new Response(file?.transformToWebStream(), {
|
return new Response(file?.transformToWebStream(), {
|
||||||
@ -34,3 +26,4 @@ async function handle(
|
|||||||
export const GET = handle;
|
export const GET = handle;
|
||||||
|
|
||||||
export const runtime = "edge";
|
export const runtime = "edge";
|
||||||
|
export const revalidate = 0;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { StructuredTool } from "langchain/tools";
|
import { StructuredTool } from "langchain/tools";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import S3FileStorage from "../../utils/r2_file_storage";
|
import S3FileStorage from "../../utils/s3_file_storage";
|
||||||
|
|
||||||
export class DallEAPIWrapper extends StructuredTool {
|
export class DallEAPIWrapper extends StructuredTool {
|
||||||
name = "dalle_image_generator";
|
name = "dalle_image_generator";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Tool } from "langchain/tools";
|
import { Tool } from "langchain/tools";
|
||||||
import S3FileStorage from "../../utils/r2_file_storage";
|
import S3FileStorage from "../../utils/s3_file_storage";
|
||||||
|
|
||||||
export class StableDiffusionWrapper extends Tool {
|
export class StableDiffusionWrapper extends Tool {
|
||||||
name = "stable_diffusion_image_generator";
|
name = "stable_diffusion_image_generator";
|
||||||
|
@ -12,13 +12,19 @@ const R2_ACCESS_KEY_ID = process.env.R2_ACCESS_KEY_ID;
|
|||||||
const R2_SECRET_ACCESS_KEY = process.env.R2_SECRET_ACCESS_KEY;
|
const R2_SECRET_ACCESS_KEY = process.env.R2_SECRET_ACCESS_KEY;
|
||||||
const R2_BUCKET = process.env.R2_BUCKET;
|
const R2_BUCKET = process.env.R2_BUCKET;
|
||||||
|
|
||||||
|
const S3_ENDPOINT = process.env.S3_ENDPOINT;
|
||||||
|
const S3_ACCESS_KEY_ID = process.env.S3_ACCESS_KEY_ID;
|
||||||
|
const S3_SECRET_ACCESS_KEY = process.env.S3_SECRET_ACCESS_KEY;
|
||||||
|
const S3_BUCKET = process.env.S3_BUCKET;
|
||||||
|
|
||||||
const getR2Client = () => {
|
const getR2Client = () => {
|
||||||
return new S3Client({
|
return new S3Client({
|
||||||
region: "auto",
|
region: "auto",
|
||||||
endpoint: `https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
|
endpoint:
|
||||||
|
S3_ENDPOINT ?? `https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
|
||||||
credentials: {
|
credentials: {
|
||||||
accessKeyId: R2_ACCESS_KEY_ID!,
|
accessKeyId: S3_ACCESS_KEY_ID ?? R2_ACCESS_KEY_ID!,
|
||||||
secretAccessKey: R2_SECRET_ACCESS_KEY!,
|
secretAccessKey: S3_SECRET_ACCESS_KEY ?? R2_SECRET_ACCESS_KEY!,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -27,7 +33,7 @@ export default class S3FileStorage {
|
|||||||
static async get(fileName: string) {
|
static async get(fileName: string) {
|
||||||
const file = await getR2Client().send(
|
const file = await getR2Client().send(
|
||||||
new GetObjectCommand({
|
new GetObjectCommand({
|
||||||
Bucket: R2_BUCKET,
|
Bucket: S3_BUCKET ?? R2_BUCKET,
|
||||||
Key: fileName,
|
Key: fileName,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -43,7 +49,7 @@ export default class S3FileStorage {
|
|||||||
const signedUrl = await getSignedUrl(
|
const signedUrl = await getSignedUrl(
|
||||||
getR2Client(),
|
getR2Client(),
|
||||||
new PutObjectCommand({
|
new PutObjectCommand({
|
||||||
Bucket: R2_BUCKET,
|
Bucket: S3_BUCKET ?? R2_BUCKET,
|
||||||
Key: fileName,
|
Key: fileName,
|
||||||
}),
|
}),
|
||||||
{ expiresIn: 60 },
|
{ expiresIn: 60 },
|
||||||
@ -59,7 +65,7 @@ export default class S3FileStorage {
|
|||||||
|
|
||||||
return `/api/file/${fileName}`;
|
return `/api/file/${fileName}`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[R2]", e);
|
console.error("[S3]", e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
68
docs/s3-oss.md
Normal file
68
docs/s3-oss.md
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# 对象存储服务配置指南
|
||||||
|
|
||||||
|
请根据自身网络情况,选择 S3 或 R2 来作为对象存储服务,两个服务配置其一即可。
|
||||||
|
|
||||||
|
由于国内网络使用 R2 经常抽风,这边推荐选择一家支持 S3 协议的对象存储服务提供商。
|
||||||
|
|
||||||
|
## 配置 S3 对象存储服务
|
||||||
|
|
||||||
|
这边以 `又拍云` 做为演示,其它运营商请查询对应文档。
|
||||||
|
|
||||||
|
1. 登录 [又拍云 - 加速在线业务 - CDN加速 - 云存储 (upyun.com)](https://www.upyun.com/)
|
||||||
|
2. 注册账户
|
||||||
|
3. 进入”云存储“控制台[又拍云控制台 (upyun.com)](https://console.upyun.com/services/file/)
|
||||||
|
4. 创建一个服务,记录你的服务名
|
||||||
|
5. 进入"用户管理","操作员"创建一个"操作员"并赋予相应权限
|
||||||
|
6. 编辑"操作员"复制"AccessKey"和"SecretAccessKey"
|
||||||
|
7. 如果读写权限未勾选则选中后确定
|
||||||
|
8. 回到 ChatGPT-Next-Web-LangChain 项目修改环境变量。按照以下信息填写:
|
||||||
|
- `S3_ENDPOINT=http://s3.api.upyun.com`
|
||||||
|
- `S3_ACCESS_KEY_ID=AccessKey`
|
||||||
|
- `S3_SECRET_ACCESS_KEY=SecretAccessKey`
|
||||||
|
- `S3_BUCKET=服务名`
|
||||||
|
9. Enjoy.
|
||||||
|
|
||||||
|
## 配置 R2 服务
|
||||||
|
登录到 dash.cloudflare.com 并在左侧菜单进入 R2。
|
||||||
|
|
||||||
|
1. 复制右侧 "账户ID"
|
||||||
|
|
||||||
|
2. 点击 "创建存储桶"。
|
||||||
|
|
||||||
|
3. 自定义配置一个存储桶名称,记录下来用于后面配置环境变量,点击 "创建存储桶"。
|
||||||
|
|
||||||
|
4. 进入 "设置",点击 "添加 CORS 策略",将下面内容粘贴上去并点击 "保存"。
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"AllowedOrigins": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"AllowedMethods": [
|
||||||
|
"PUT",
|
||||||
|
"DELETE",
|
||||||
|
"GET"
|
||||||
|
],
|
||||||
|
"AllowedHeaders": [
|
||||||
|
"content-type"
|
||||||
|
],
|
||||||
|
"MaxAgeSeconds": 3000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
5. 回到 R2 主菜单,点击右侧 "管理 R2 API 令牌"。
|
||||||
|
|
||||||
|
6. 点击 "创建 API 令牌",权限选择为 "管理员读和写",TTL 选择为 "永久",点击 "创建 API 令牌"。
|
||||||
|
|
||||||
|
7. 复制 "访问密钥 ID" 和 "机密访问密钥",点击 "完成"。
|
||||||
|
|
||||||
|
8. 回到 ChatGPT-Next-Web-LangChain 项目修改环境变量。按照以下信息填写:
|
||||||
|
|
||||||
|
- `R2_ACCOUNT_ID=账户ID`
|
||||||
|
- `R2_ACCESS_KEY_ID=访问密钥 ID`
|
||||||
|
- `R2_SECRET_ACCESS_KEY=机密访问密钥`
|
||||||
|
- `R2_BUCKET=存储桶名称`
|
||||||
|
|
||||||
|
9. Enjoy.
|
Loading…
Reference in New Issue
Block a user