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

feat: support password #28

Merged
merged 1 commit into from
Apr 19, 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
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