Skip to content

Commit

Permalink
🐛 fix: fix envs like CUSTOM_MODELS don't work with docker deploymen…
Browse files Browse the repository at this point in the history
…t (#773)

* ♻️ refactor: refactor the FileList

* 🐛 fix: fix agent market index not work with docker

* 🐛 fix: fix CUSTOM_MODEL don't work with docker deployment

* ✅ test: add test

* 📝 docs: update docs
  • Loading branch information
arvinxx committed Dec 23, 2023
1 parent 75c1126 commit 54dc18b
Show file tree
Hide file tree
Showing 35 changed files with 243 additions and 264 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
ACCESS_CODE=lobe66

# add your custom model name, multi model separate by comma. for example gpt-3.5-1106,gpt-4-1106
# NEXT_PUBLIC_CUSTOM_MODELS=model1,model2,model3
# CUSTOM_MODELS=model1,model2,model3

# ---- only choose one from OpenAI Service and Azure OpenAI Service ---- #

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ ENV PORT=3210

# General Variables
ENV ACCESS_CODE "lobe66"
ENV NEXT_PUBLIC_CUSTOM_MODELS ""
ENV CUSTOM_MODELS ""

# OpenAI
ENV OPENAI_API_KEY ""
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -391,12 +391,12 @@ $ docker run -d -p 3210:3210 \

This project provides some additional configuration items set with environment variables:

| Environment Variable | Required | Description | Example |
| ------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `OPENAI_API_KEY` | Yes | This is the API key you apply on the OpenAI account page | `sk-xxxxxx...xxxxxx` |
| `OPENAI_PROXY_URL` | No | If you manually configure the OpenAI interface proxy, you can use this configuration item to override the default OpenAI API request base URL | `https://api.chatanywhere.cn/v1`<br/>The default value is<br/>`https://api.openai.com/v1` |
| `OPENAI_FUNCTION_REGIONS` | No | When you deploy Lobe-Chat using Vercel and need to specify the region for the Edge Function that handles requests to the OpenAI API, you can use this configuration. The value should be a comma-separated array of strings. | `iad1,sfo1` |
| `ACCESS_CODE` | No | Add a password to access this service; you can set a long password to avoid leaking. If this value contains a comma, it is a password array. | `awCTe)re_r74` or `rtrt_ewee3@09!` or `code1,code2,code3` |
| Environment Variable | Required | Description | Example |
| -------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `OPENAI_API_KEY` | Yes | This is the API key you apply on the OpenAI account page | `sk-xxxxxx...xxxxxx` |
| `OPENAI_PROXY_URL` | No | If you manually configure the OpenAI interface proxy, you can use this configuration item to override the default OpenAI API request base URL | `https://api.chatanywhere.cn/v1`<br/>The default value is<br/>`https://api.openai.com/v1` |
| `ACCESS_CODE` | No | Add a password to access this service; you can set a long password to avoid leaking. If this value contains a comma, it is a password array. | `awCTe)re_r74` or `rtrt_ewee3@09!` or `code1,code2,code3` |
| `CUSTOM_MODELS` | No | Used to control the model list. Use `+` to add a model, `-` to hide a model, and `model_name=display_name` to customize the display name of a model, separated by commas. | `qwen-7b-chat,+glm-6b,-gpt-3.5-turbo` |

> \[!NOTE]
>
Expand Down
12 changes: 6 additions & 6 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -363,12 +363,12 @@ $ docker run -d -p 3210:3210 \

本项目提供了一些额外的配置项,使用环境变量进行设置:

| 环境变量 | 类型 | 描述 | 示例 |
| ------------------------- | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| `OPENAI_API_KEY` | 必选 | 这是你在 OpenAI 账户页面申请的 API 密钥 | `sk-xxxxxx...xxxxxx` |
| `OPENAI_PROXY_URL` | 可选 | 如果你手动配置了 OpenAI 接口代理,可以使用此配置项来覆盖默认的 OpenAI API 请求基础 URL | `https://api.chatanywhere.cn/v1`<br/>默认值:<br/>`https://api.openai.com/v1` |
| `OPENAI_FUNCTION_REGIONS` | 可选 | 当你使用 Vercel 部署 Lobe-Chat,而且有需求指定响应调用 OpenAI 接口的请求的 Edge Function 的 Region 时,可以使用该配置进行配置,该值的类型为逗号分隔的字符串数组 | `iad1,sfo1` |
| `ACCESS_CODE` | 可选 | 添加访问此服务的密码,你可以设置一个长密码以防被爆破,该值用逗号分隔时为密码数组 | `awCTe)re_r74` or `rtrt_ewee3@09!` or `code1,code2,code3` |
| 环境变量 | 类型 | 描述 | 示例 |
| ------------------ | ---- | ----------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| `OPENAI_API_KEY` | 必选 | 这是你在 OpenAI 账户页面申请的 API 密钥 | `sk-xxxxxx...xxxxxx` |
| `OPENAI_PROXY_URL` | 可选 | 如果你手动配置了 OpenAI 接口代理,可以使用此配置项来覆盖默认的 OpenAI API 请求基础 URL | `https://api.chatanywhere.cn/v1`<br/>默认值:<br/>`https://api.openai.com/v1` |
| `ACCESS_CODE` | 可选 | 添加访问此服务的密码,你可以设置一个长密码以防被爆破,该值用逗号分隔时为密码数组 | `awCTe)re_r74` or `rtrt_ewee3@09!` or `code1,code2,code3` |
| `CUSTOM_MODELS` | 可选 | 用来控制模型列表,使用 `+` 增加一个模型,使用 `-` 来隐藏一个模型,使用 `模型名=展示名` 来自定义模型的展示名,用英文逗号隔开。 | `qwen-7b-chat,+glm-6b,-gpt-3.5-turbo` |

> \[!NOTE]
>
Expand Down
4 changes: 2 additions & 2 deletions docs/Deployment/Environment-Variable.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ LobeChat provides additional configuration options during deployment, which can

- [General Variables](#general-variables)
- [`ACCESS_CODE`](#access_code)
- [`NEXT_PUBLIC_CUSTOM_MODELS`](#next_public_custom_models)
- [`CUSTOM_MODELS`](#custom_models)
- [OpenAI](#openai)
- [`OPENAI_API_KEY`](#openai_api_key)
- [`OPENAI_PROXY_URL`](#openai_proxy_url)
Expand All @@ -31,7 +31,7 @@ LobeChat provides additional configuration options during deployment, which can
- Default: `-`
- Example: `awCTe)re_r74` or `rtrt_ewee3@09!` or `code1,code2,code3`

### `NEXT_PUBLIC_CUSTOM_MODELS`
### `CUSTOM_MODELS`

- Type: Optional
- Description: Used to control the model list. Use `+` to add a model, `-` to hide a model, and `model_name=display_name` to customize the display name of a model, separated by commas.
Expand Down
4 changes: 2 additions & 2 deletions docs/Deployment/Environment-Variable.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ LobeChat 在部署时提供了一些额外的配置项,使用环境变量进

- [通用变量](#通用变量)
- [`ACCESS_CODE`](#access_code)
- [`NEXT_PUBLIC_CUSTOM_MODELS`](#next_public_custom_models)
- [`CUSTOM_MODELS`](#custom_models)
- [OpenAI](#openai)
- [`OPENAI_API_KEY`](#openai_api_key)
- [`OPENAI_PROXY_URL`](#openai_proxy_url)
Expand All @@ -31,7 +31,7 @@ LobeChat 在部署时提供了一些额外的配置项,使用环境变量进
- 默认值:-
- 示例:`awCTe)re_r74` or `rtrt_ewee3@09!`

### `NEXT_PUBLIC_CUSTOM_MODELS`
### `CUSTOM_MODELS`

- 类型:可选
- 描述:用来控制模型列表,使用 `+` 增加一个模型,使用 `-` 来隐藏一个模型,使用 `模型名=展示名` 来自定义模型的展示名,用英文逗号隔开。
Expand Down
4 changes: 0 additions & 4 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ const withPWA = nextPWA({
/** @type {import('next').NextConfig} */
const nextConfig = {
compress: isProd,
env: {
AGENTS_INDEX_URL: process.env.AGENTS_INDEX_URL ?? '',
PLUGINS_INDEX_URL: process.env.PLUGINS_INDEX_URL ?? '',
},
experimental: {
forceSwcTransforms: true,
optimizePackageImports: [
Expand Down
15 changes: 15 additions & 0 deletions src/app/api/config/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { getServerConfig } from '@/config/server';
import { GlobalServerConfig } from '@/types/settings';

export const runtime = 'edge';

/**
* get Server config to client
*/
export const GET = async () => {
const { CUSTOM_MODELS } = getServerConfig();

const config: GlobalServerConfig = { customModelName: CUSTOM_MODELS };

return new Response(JSON.stringify(config));
};
25 changes: 25 additions & 0 deletions src/app/api/market/AgentMarket.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import urlJoin from 'url-join';

import { getServerConfig } from '@/config/server';
import { DEFAULT_LANG, checkLang } from '@/const/locale';
import { Locales } from '@/locales/resources';

export class AgentMarket {
private readonly baseUrl: string;

constructor(baseUrl?: string) {
this.baseUrl = baseUrl || getServerConfig().AGENTS_INDEX_URL;
}

getAgentIndexUrl = (lang: Locales = DEFAULT_LANG) => {
if (checkLang(lang)) return this.baseUrl;

return urlJoin(this.baseUrl, `index.${lang}.json`);
};

getAgentUrl = (identifier: string, lang: Locales = DEFAULT_LANG) => {
if (checkLang(lang)) return urlJoin(this.baseUrl, `${identifier}.json`);

return urlJoin(this.baseUrl, `${identifier}.${lang}.json`);
};
}
9 changes: 6 additions & 3 deletions src/app/api/market/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { DEFAULT_LANG } from '@/const/locale';
import { getAgentJSON } from '@/const/url';

import { AgentMarket } from '../AgentMarket';

export const runtime = 'edge';

Expand All @@ -8,11 +9,13 @@ export const GET = async (req: Request, { params }: { params: { id: string } })

const locale = searchParams.get('locale');

const market = new AgentMarket();

let res: Response;

res = await fetch(getAgentJSON(params.id, locale as any));
res = await fetch(market.getAgentUrl(params.id, locale as any));
if (res.status === 404) {
res = await fetch(getAgentJSON(params.id, DEFAULT_LANG));
res = await fetch(market.getAgentUrl(params.id, DEFAULT_LANG));
}

return res;
Expand Down
9 changes: 6 additions & 3 deletions src/app/api/market/route.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { DEFAULT_LANG } from '@/const/locale';
import { getAgentIndexJSON } from '@/const/url';

import { AgentMarket } from './AgentMarket';

export const runtime = 'edge';

export const GET = async (req: Request) => {
const locale = new URL(req.url).searchParams.get('locale');

const market = new AgentMarket();

let res: Response;

res = await fetch(getAgentIndexJSON(locale as any));
res = await fetch(market.getAgentIndexUrl(locale as any));

if (res.status === 404) {
res = await fetch(getAgentIndexJSON(DEFAULT_LANG));
res = await fetch(market.getAgentIndexUrl(DEFAULT_LANG));
}

return res;
Expand Down
2 changes: 1 addition & 1 deletion src/components/FileList/EditableFileList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useResponsive } from 'antd-style';
import { memo } from 'react';
import { Flexbox } from 'react-layout-kit';

import ImageFileItem from '@/components/FileList/ImageFileItem';
import ImageFileItem from './ImageFileItem';

interface EditableFileListProps {
alwaysShowClose?: boolean;
Expand Down
36 changes: 0 additions & 36 deletions src/components/FileList/FileGrid.tsx

This file was deleted.

48 changes: 3 additions & 45 deletions src/components/FileList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,18 @@
import { ImageGallery } from '@lobehub/ui';
import { useResponsive } from 'antd-style';
import { memo, useMemo } from 'react';
import { Flexbox } from 'react-layout-kit';
import { memo } from 'react';

import { MAX_SIZE_DESKTOP, MAX_SIZE_MOBILE } from '@/components/FileList/style';
import GalleyGrid from '@/components/GalleyGrid';

import FileGrid from './FileGrid';
import ImageFileItem from './ImageFileItem';

interface FileListProps {
items: string[];
}

const FileList = memo<FileListProps>(({ items }) => {
const { mobile } = useResponsive();

const { firstRow, lastRow } = useMemo(() => {
if (items.length === 4) {
return {
firstRow: items.slice(0, 2),
lastRow: items.slice(2, 4),
};
}

const firstCol = items.length % 3 === 0 ? 3 : items.length % 3;

return {
firstRow: items.slice(0, firstCol),
lastRow: items.slice(firstCol, items.length),
};
}, [items]);

const { gap, max } = useMemo(
() => ({
gap: mobile ? 4 : 6,
max: mobile ? MAX_SIZE_MOBILE : MAX_SIZE_DESKTOP,
}),
[mobile],
);

return (
<ImageGallery>
<Flexbox gap={gap}>
<FileGrid col={firstRow.length} gap={gap} max={max}>
{firstRow.map((i) => (
<ImageFileItem id={i} key={i} />
))}
</FileGrid>
{lastRow.length > 0 && (
<FileGrid col={lastRow.length > 2 ? 3 : lastRow.length} gap={gap} max={max}>
{lastRow.map((i) => (
<ImageFileItem id={i} key={i} />
))}
</FileGrid>
)}
</Flexbox>
<GalleyGrid items={items} renderItem={ImageFileItem} />
</ImageGallery>
);
});
Expand Down
23 changes: 0 additions & 23 deletions src/components/FileList/style.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1 @@
import { createStyles } from 'antd-style';

export const MIN_IMAGE_SIZE = 64;
export const MAX_SIZE_DESKTOP = 640;
export const MAX_SIZE_MOBILE = 280;
export const useStyles = createStyles(
({ css }, { col, gap, max, min }: { col: number; gap: number; max: number; min: number }) => ({
container: css`
display: grid;
grid-gap: ${gap}px;
grid-template-columns: repeat(${col}, 1fr);
width: 100%;
max-width: ${max}px;
& > div {
width: 100%;
min-width: ${min}px;
min-height: ${min}px;
max-height: ${(max - gap * (col - 1)) / col}px;
}
`,
}),
);
23 changes: 0 additions & 23 deletions src/config/__tests__/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,6 @@ vi.stubGlobal('process', {
});

describe('getClientConfig', () => {
it('should return default URLs when no environment variables are set', () => {
const config = getClientConfig();
expect(config.AGENTS_INDEX_URL).toBe('https://chat-agents.lobehub.com');
expect(config.PLUGINS_INDEX_URL).toBe('https://chat-plugins.lobehub.com');
});

it('should return custom URLs when environment variables are set', () => {
process.env.AGENTS_INDEX_URL = 'https://custom-agents-url.com';
process.env.PLUGINS_INDEX_URL = 'https://custom-plugins-url.com';
const config = getClientConfig();
expect(config.AGENTS_INDEX_URL).toBe('https://custom-agents-url.com');
expect(config.PLUGINS_INDEX_URL).toBe('https://custom-plugins-url.com');
});

it('should return default URLs when environment variables are empty string', () => {
process.env.AGENTS_INDEX_URL = '';
process.env.PLUGINS_INDEX_URL = '';

const config = getClientConfig();
expect(config.AGENTS_INDEX_URL).toBe('https://chat-agents.lobehub.com');
expect(config.PLUGINS_INDEX_URL).toBe('https://chat-plugins.lobehub.com');
});

it('should correctly reflect boolean values for analytics flags', () => {
process.env.NEXT_PUBLIC_ANALYTICS_VERCEL = '1';
process.env.NEXT_PUBLIC_VERCEL_DEBUG = '1';
Expand Down
27 changes: 26 additions & 1 deletion src/config/__tests__/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('getServerConfig', () => {
global.process = undefined;

expect(() => getServerConfig()).toThrow(
'[Server Config] you are importing a nodejs-only module outside of nodejs',
'[Server Config] you are importing a server-only module outside of server',
);

global.process = originalProcess; // Restore the original process object
Expand Down Expand Up @@ -55,4 +55,29 @@ describe('getServerConfig', () => {
const config = getServerConfig();
expect(config.IMGUR_CLIENT_ID).toBe('custom-client-id');
});

describe('index url', () => {
it('should return default URLs when no environment variables are set', () => {
const config = getServerConfig();
expect(config.AGENTS_INDEX_URL).toBe('https://chat-agents.lobehub.com');
expect(config.PLUGINS_INDEX_URL).toBe('https://chat-plugins.lobehub.com');
});

it('should return custom URLs when environment variables are set', () => {
process.env.AGENTS_INDEX_URL = 'https://custom-agents-url.com';
process.env.PLUGINS_INDEX_URL = 'https://custom-plugins-url.com';
const config = getServerConfig();
expect(config.AGENTS_INDEX_URL).toBe('https://custom-agents-url.com');
expect(config.PLUGINS_INDEX_URL).toBe('https://custom-plugins-url.com');
});

it('should return default URLs when environment variables are empty string', () => {
process.env.AGENTS_INDEX_URL = '';
process.env.PLUGINS_INDEX_URL = '';

const config = getServerConfig();
expect(config.AGENTS_INDEX_URL).toBe('https://chat-agents.lobehub.com');
expect(config.PLUGINS_INDEX_URL).toBe('https://chat-plugins.lobehub.com');
});
});
});
Loading

0 comments on commit 54dc18b

Please sign in to comment.