Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 fix: fix envs like CUSTOM_MODELS don't work with docker deployment #773

Merged
merged 5 commits into from
Dec 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading