Skip to content

Commit

Permalink
feat: support password (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
lvqq authored Apr 19, 2023
1 parent 9234151 commit cd76f2e
Show file tree
Hide file tree
Showing 13 changed files with 83 additions and 32 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
PASSWORD=
OPENAI_API_KEY=
LANGUAGE=en
OPENAI_API_BASE_URL=api.openai.com
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ You can access the online demo above or deploy it privately for experience.
Click the icon at the top left to add a conversation, which has two types:
- Text conversation:
- The model is switchable, [supported models](https://platform.openai.com/docs/models/model-endpoint-compatibility)
- By default, it is a continuous conversation, and each sending will carry the full context.
- By default, it is a continuous conversation, and each sending will carry part of context.
- Supports adding preset prompts, type `/` or click the button at the bottom left to add.
- Supports model configuration, click the settings icon at the top right to configure.
- Image generation conversation:
Expand Down Expand Up @@ -71,14 +71,15 @@ There are three ways to set your OpenAI API Key:
> Attention: For Vercel, all environment variables need to be redeployed to take effect.
## Other deployment methods
Run `pnpm build` and `pnpm server`. Refer: [astro-node](https://docs.astro.build/en/guides/integrations-guide/node/#standalone)
Run `pnpm build` and `pnpm run server`. Refer: [astro-node](https://docs.astro.build/en/guides/integrations-guide/node/#standalone)

## Configurations
### Deployment Configurations
All deployment configurations could be configured in the `.env` file or in **Environment Variables** of Vercel

| Configuration | Default Value | Description |
| ------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| PASSWORD | - | Website access password |
| OPENAI_API_KEY | - | Key for API request, multiple keys are supported, separated by commas, [how to generate](https://platform.openai.com/account/api-keys)|
| LANGUAGE | en | The default language of the website, including prompts. Supported languages: **zh**/**en** |
| API_KEY_STRATEGY | random | The scheduling strategy mode for multiple keys: **polling**/**random** |
Expand Down Expand Up @@ -129,7 +130,7 @@ Any contributions are highly appreciated. Here are some tips:
- To improve the translation or add a new language, modify the `lang` directory. If adding a new language, you will also need to modify `src/utils/i18n.ts`.
- To improve or add new preset prompts, modify the `prompts` directory.
- To optimize the API, modify the `src/pages/api` directory.
- To optimize page interactions, modify the `src/components` directory.
- To optimize page interactions, modify the `src/modules` directory.
- For new feature support, please open an issue directly.

## Credits
Expand Down
7 changes: 4 additions & 3 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
点击左上角可以添加对话,有两种类型:
- 文本对话:
- 模型可选,[支持的所有模型](https://platform.openai.com/docs/models/model-endpoint-compatibility)
- 默认为连续对话,每次发送会携带全量上下文
- 默认为连续对话,每次发送会携带部分上下文
- 支持添加预设提示,输入`/`或者点击左下角按钮添加
- 支持模型配置,点击右上角设置图标进行配置
- 图像生成对话:
Expand Down Expand Up @@ -82,14 +82,15 @@
> vercel.app 域名受限,但 vercel 本身并未受限
## 其他部署方式
运行 `pnpm run build``pnpm run server`,参考:[astro-node](https://docs.astro.build/en/guides/integrations-guide/node/#standalone)
运行 `pnpm build``pnpm run server`,参考:[astro-node](https://docs.astro.build/en/guides/integrations-guide/node/#standalone)

## 配置
### 部署配置
所有部署配置都可以在 `.env` 文件或者 Vercel 的环境变量中配置

| 配置项 | 默认值 | 描述 |
| ------------------- | -------------- | -------------------------------------------------------------------------------------------------- |
| PASSWORD | - | 网站的访问密码 |
| OPENAI_API_KEY | - | Api 请求使用的 key, 支持多个 key,以逗号分隔,[如何生成](https://platform.openai.com/account/api-keys) |
| LANGUAGE | en | 站点的默认语言,包含预设提示,支持的语言: **zh**/**en** |
| API_KEY_STRATEGY | random | 多个 key 时的调度策略模式:轮询(**polling**)、随机(**random**|
Expand Down Expand Up @@ -140,7 +141,7 @@
- 改善翻译或者新增语言,修改 `lang` 目录,新增语言还需要修改 `src/utils/i18n.ts`
- 改善或者新增预设提示,修改 `prompts` 目录
- 优化 API,修改 `src/pages/api` 目录
- 优化页面交互,修改 `src/components` 目录
- 优化页面交互,修改 `src/modules` 目录
- 新增功能支持,可以直接提 issue

## 致谢
Expand Down
1 change: 1 addition & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"config_images_count": "Number of generated images:",
"config_images_size": "Size of generated images:",
"config_language": "Language:",
"config_password": "Password:",
"status_loading": "AI is thinking...",
"status_empty": "New Conversation",
"status_image_expired": "Image has expired",
Expand Down
1 change: 1 addition & 0 deletions lang/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"config_images_count": "生成图片数:",
"config_images_size": "图片尺寸:",
"config_language": "语言:",
"config_password": "访问密码:",
"status_loading": "AI 正在思考...",
"status_empty": "新的对话",
"status_image_expired": "图片已过期",
Expand Down
1 change: 1 addition & 0 deletions src/configs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const supportedLanguages = [
];

export const defaultGloablConfig: GlobalConfig = {
password: '',
openAIApiKey: '',
model: defaultModel,
save: true,
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface Conversation {
}

export interface GlobalConfig {
password: string;
openAIApiKey: string;
model: SupportedModel;
save: boolean;
Expand Down
12 changes: 12 additions & 0 deletions src/modules/Configuration/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ const Configuration: FC<ConfigurationProps> = ({
</div>
</div>
<div className="pl-5 pr-5 pt-4 pb-4 text-sm flex flex-1 flex-col overflow-auto common-scrollbar">
<div className="mb-6">
<div className="mb-2">{i18n.config_password}</div>
<Input
className="w-full"
type="password"
autoComplete="off"
value={configs.password}
onChange={(e) =>
updateConfigsAndStorages({ password: e.target.value })
}
/>
</div>
<div className="mb-6">
<div className="mb-2">OpenAI Api Key:</div>
<Input
Expand Down
2 changes: 2 additions & 0 deletions src/modules/Content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ const Content: FC<ContentProps> = ({ setActiveSetting }) => {
? allMessages.slice(-1 * (configs.messagesCount ?? 4) - 1)
: input,
temperature: configs.temperature ?? 1,
password: configs.password,
}),
signal: abortController.signal,
});
Expand Down Expand Up @@ -214,6 +215,7 @@ const Content: FC<ContentProps> = ({ setActiveSetting }) => {
prompt: content,
size: configs.imageSize || '256x256',
n: configs.imagesCount || 1,
password: configs.password,
}),
});
const { data = [], msg } = await res.json();
Expand Down
54 changes: 32 additions & 22 deletions src/modules/Main.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC, useEffect, useLayoutEffect, useState } from 'react';
import { FC, useCallback, useEffect, useLayoutEffect, useState } from 'react';
import GlobalContext from '@contexts/global';
import {
defaultConversation,
Expand Down Expand Up @@ -58,6 +58,33 @@ const Main: FC<{ lang: Lang }> = ({ lang }) => {
window.addEventListener('resize', handleDebounceResize);
}, []);

const setConversationsFromLocal = useCallback(() => {
try {
const localConversation = localStorage.getItem(localConversationKey);
if (localConversation) {
const conversation = JSON.parse(localConversation);
// historical localstorage
if (Array.isArray(conversation) && conversation.length > 0) {
setConversations({
[defaultConversation.id]: {
title: conversation[0].content,
messages: conversation,
id: defaultConversation.id,
createdAt: Date.now(),
},
});
} else {
setConversations(conversation);
setCurrentId(
Object.keys(conversation)?.reverse()?.[0] ?? defaultConversation.id
);
}
}
} catch (e) {
//
}
}, []);

useEffect(() => {
const defaultConfigs = {
...defaultGloablConfig,
Expand All @@ -74,33 +101,16 @@ const Main: FC<{ lang: Lang }> = ({ lang }) => {
...localConfigs,
}));
if (localConfigs.save) {
const localConversation = localStorage.getItem(localConversationKey);
if (localConversation) {
const conversation = JSON.parse(localConversation);
// historical localstorage
if (Array.isArray(conversation) && conversation.length > 0) {
setConversations({
[defaultConversation.id]: {
title: conversation[0].content,
messages: conversation,
id: defaultConversation.id,
createdAt: Date.now(),
},
});
} else {
setConversations(conversation);
setCurrentId(
Object.keys(conversation)?.reverse()?.[0] ??
defaultConversation.id
);
}
}
setConversationsFromLocal();
}
} catch (e) {
setConfigs(defaultConfigs);
}
} else {
setConfigs(defaultConfigs);
if (defaultConfigs.save) {
setConversationsFromLocal();
}
}
}, []);

Expand Down
13 changes: 11 additions & 2 deletions src/pages/api/completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { createParser } from 'eventsource-parser';
import { defaultModel, supportedModels } from '@configs';
import { Message } from '@interfaces';
import { loadBalancer } from '@utils/server';
import { apiKeyStrategy, apiKeys, baseURL, config } from '.';
import { apiKeyStrategy, apiKeys, baseURL, config, password as pwd } from '.';

export { config };

Expand All @@ -17,7 +17,7 @@ export const post: APIRoute = async ({ request }) => {
}

const body = await request.json();
const { messages, temperature = 1 } = body;
const { messages, temperature = 1, password } = body;
let { key, model } = body;

if (!key) {
Expand All @@ -27,6 +27,15 @@ export const post: APIRoute = async ({ request }) => {

model = model || defaultModel;

if (pwd && password !== pwd) {
return new Response(
JSON.stringify({ msg: 'No password or wrong password' }),
{
status: 401,
}
);
}

if (!key) {
return new Response(JSON.stringify({ msg: 'No API key provided' }), {
status: 400,
Expand Down
13 changes: 11 additions & 2 deletions src/pages/api/images.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable no-console */
import type { APIRoute } from 'astro';
import { loadBalancer } from '@utils/server';
import { apiKeyStrategy, apiKeys, baseURL, config } from '.';
import { apiKeyStrategy, apiKeys, baseURL, config, password as pwd } from '.';

export { config };

Expand All @@ -13,14 +13,23 @@ export const post: APIRoute = async ({ request }) => {
}

const body = await request.json();
const { prompt, size = '256x256', n = 1 } = body;
const { prompt, size = '256x256', n = 1, password } = body;
let { key } = body;

if (!key) {
const next = loadBalancer(apiKeys, apiKeyStrategy);
key = next();
}

if (pwd && password !== pwd) {
return new Response(
JSON.stringify({ msg: 'No password or wrong password' }),
{
status: 401,
}
);
}

if (!key) {
return new Response(JSON.stringify({ msg: 'No API key provided' }), {
status: 400,
Expand Down
2 changes: 2 additions & 0 deletions src/pages/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export const baseURL = (
export const apiKeyStrategy: StrategyMode =
import.meta.env.API_KEY_STRATEGY || process.env.API_KEY_STRATEGY || 'random';

export const password = import.meta.env.PASSWORD || process.env.PASSWORD;

/**
* https://vercel.com/docs/concepts/edge-network/regions#region-list
* disable hkg1 HongKong
Expand Down

0 comments on commit cd76f2e

Please sign in to comment.