Skip to content

Commit

Permalink
feat: support image generation model Midjourney (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
lvqq authored Apr 27, 2023
1 parent b0bb4b4 commit 99ed02c
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 29 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<a href="https://github.com/GPTGenius/chatgpt-vercel/tags">
<img alt="GitHub tag (latest by date)" src="https://img.shields.io/github/v/release/GPTGenius/chatgpt-vercel">
</a>
<img alt="node-current (scoped)" src="https://img.shields.io/node/v/replicate-fetch">
<a href="https://github.com/GPTGenius/chatgpt-vercel/blob/main/LICENSE">
<img alt="license" src="https://img.shields.io/github/license/GPTGenius/chatgpt-vercel">
</a>
Expand All @@ -19,7 +20,7 @@ Create a private ChatGPT website with one-click for free using Vercel, support m
## Features
- ⚡ Deploy quickly and for free using Vercel
- 💬 Text conversation with the ability to switch models and set context length
- 🎨 Image generation conversation with options to adjust image size and count
- 🎨 Image generation conversation supports the `DALL-E` and `Midjourney` models. It also allows for the adjustment of image size and count.
- 🌈 Multiple preset prompts added to customize AI behavior
- 🌏 Switch between various languages, currently supporting Simplified Chinese and English
- 💭 Local chat history saved with search, import and export functionality
Expand All @@ -39,10 +40,11 @@ Click the icon at the top left to add a conversation, which has two types:
- 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:
- The model is fixed and based on the OpenAI DALL·E model
- The model is switchable, supports the OpenAI `DALL·E` model and `Midjourney`
- Does not support continuous conversation, and each sending will not carry the context.
- Directly input the image effect you want, for example: `a cat`.
- The valid access time of the image link is `2` hours. Please save it in time if necessary.
- For model `DALL·E`, the valid access time of the image link is `2` hours. Please save it in time if necessary.
- For model `Midjourney`, it is recommended to add the prefix `mdjrny-v4 style`

### History record
When `Save all conversations` is enabled in the global settings, it will be saved to local cache. By default, it will not be saved.
Expand Down Expand Up @@ -105,13 +107,13 @@ All global configurations will be stored locally
- [ ] Export functionality to export as markdown and images
- [ ] Theme color switching support, currently defaulting to gradient purple
- [ ] Audio conversation support
- [ ] Image generation using other models
- [x] Image generation using other models

These are some of the planned features to be developed. Collaborations are welcome, and feel free to suggest other ideas by submitting issues.

## Development
Requirements:
- **NodeJS** `v16.12.0` or higher
- **NodeJS** `v18` or higher
- **pnpm** `v7` or higher

Proxy
Expand Down
12 changes: 7 additions & 5 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<a href="https://github.com/GPTGenius/chatgpt-vercel/tags">
<img alt="GitHub tag (latest by date)" src="https://img.shields.io/github/v/release/GPTGenius/chatgpt-vercel">
</a>
<img alt="node-current (scoped)" src="https://img.shields.io/node/v/replicate-fetch">
<a href="https://github.com/GPTGenius/chatgpt-vercel/blob/main/LICENSE">
<img alt="license" src="https://img.shields.io/github/license/GPTGenius/chatgpt-vercel">
</a>
Expand All @@ -20,7 +21,7 @@
## 主要功能
- ⚡ 通过 Vercel 一键免费部署,添加自己的域名即可无障碍访问
- 💬 文本对话,可以自由切换模型,设置上下文长度
- 🎨 图像生成对话,支持调整图片大小和图片数量
- 🎨 图像生成对话,支持 `DALL-E``Midjourney` 模型,可以调整图片大小和数量
- 🌈 添加多种预设提示,定制 AI 行为
- 🌏 切换多种语言,目前支持 简体中文、英语
- 💭 聊天记录本地保存,支持搜索、导入和导出等
Expand All @@ -40,10 +41,11 @@
- 支持添加预设提示,输入`/`或者点击左下角按钮添加
- 支持模型配置,点击右上角设置图标进行配置
- 图像生成对话:
- 模型固定,基于 OpenAI DALL·E 模型
- 模型可选,支持 OpenAI `DALL·E` 模型和 `Midjourney` 模型
- 不支持连续对话,每次发送不会携带上下文
- 直接输入你想要的图片效果,例如:`一只猫`
- 图片链接的有效访问时间为 `2` 小时,如有需要请及时保存
- 对于 `DALL·E` 模型,图片链接的有效访问时间为 `2` 小时,如有需要请及时保存
- 对于 `Midjourney` 模型,推荐使用英文并加上前缀 `mdjrny-v4 style`

### 历史记录
全局设置中开启`保留所有会话`时会保存到本地缓存,默认不保存
Expand Down Expand Up @@ -116,13 +118,13 @@
- [ ] 支持导出功能,导出 markdown & 图片
- [ ] 支持主题色切换,目前默认为渐变紫色
- [ ] 支持音频对话
- [ ] 支持通过其他模型生成图片
- [x] 支持通过其他模型生成图片

以上是计划开发的一些功能,欢迎共建,有其他想法也可以提相关 issue

## 本地开发
需要:
- **NodeJS** `v16.12.0` 或更高版本
- **NodeJS** `v18` 或更高版本
- **pnpm** `v7` 或更高版本

代理:
Expand Down
2 changes: 1 addition & 1 deletion lang/en.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"default_text_tips": "Powered by OpenAI and Vercel\n- Chat with us now. Press `Enter` to send and `Shift`+`Enter` to add a new line. \n- Input `/` or click the button at the bottom left to add a preset prompt",
"default_image_tips": "Powered by OpenAI and Vercel\n- Chat with us now. Press `Enter` to send and `Shift`+`Enter` to add a new line. \n- The image generation does not support continuous dialogue. Please input directly the desired image effect, for example: `a cat`.\n- The effective access time for the image link is `2` hours. Please make sure to save it in time if necessary.",
"default_image_tips": "Powered by OpenAI, Replicate and Vercel\n- Chat with us now. Press `Enter` to send and `Shift`+`Enter` to add a new line. \n- The image generation does not support continuous dialogue. Please input directly the desired image effect, for example: `a cat`.\n- For model `DALL-E`, the effective access time for the image link is `2` hours. Please make sure to save it in time if necessary.\n- For model `Midjourney`, it is recommended to add the prefix `mdjrny-v4 style`",
"chat_placeholder": "Start a conversation",
"empty_conversation": "Please select a conversation",
"search_placeholder": "Search",
Expand Down
2 changes: 1 addition & 1 deletion lang/zh.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"default_text_tips": "由 OpenAI 和 Vercel 提供支持\n- 点击下方发起聊天,`Enter`键发送,`Shift`+`Enter`键换行\n- 输入`/`或者点击左下角按钮添加预设提示",
"default_image_tips": "由 OpenAI 和 Vercel 提供支持\n- 点击下方发起聊天,`Enter`键发送,`Shift`+`Enter`键换行\n- 图片生成不支持连续对话,直接输入你想要的图片效果,例如:`一只猫`\n- 图片链接的有效访问时间为 `2` 小时,如有需要请及时保存",
"default_image_tips": "由 OpenAI、Replicate 和 Vercel 提供支持\n- 点击下方发起聊天,`Enter`键发送,`Shift`+`Enter`键换行\n- 图片生成不支持连续对话,直接输入你想要的图片效果,例如:`一只猫`\n- 对于 `DALL-E` 模型,图片链接的有效访问时间为 `2` 小时,如有需要请及时保存\n- 对于 `Midjourney` 模型,推荐使用英文且加上前缀 `mdjrny-v4 style`",
"chat_placeholder": "开始聊天",
"empty_conversation": "请点击左侧对话",
"search_placeholder": "搜索",
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"license": "MIT",
"packageManager": "pnpm@7.29.3",
"engines": {
"node": ">=16.12.0",
"node": ">=18",
"pnpm": ">=7.29.0 <8"
},
"scripts": {
Expand Down Expand Up @@ -41,6 +41,7 @@
"markdown-it-kbd": "^2.2.2",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"replicate-fetch": "^0.1.1",
"solid-js": "^1.6.15"
},
"devDependencies": {
Expand Down
7 changes: 7 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions src/configs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ export type SupportedModel = (typeof supportedModels)[number];

export const defaultModel: SupportedModel = 'gpt-3.5-turbo';

export const supportedImageModels = ['DALL-E', 'Midjourney'] as const;

export type SupportedImageModels = (typeof supportedImageModels)[number];

export const defaultImageModel: SupportedImageModels = 'DALL-E';

// From https://platform.openai.com/docs/api-reference/images/create
export const supportedImgSizes = ['256x256', '512x512', '1024x1024'] as const;

Expand All @@ -37,6 +43,7 @@ export const defaultGloablConfig: GlobalConfig = {
password: '',
openAIApiKey: '',
model: defaultModel,
imageModel: defaultImageModel,
save: true,
continuous: true,
messagesCount: 4,
Expand Down
9 changes: 7 additions & 2 deletions src/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { SupportedImgSize, SupportedModel } from '@configs';
import {
SupportedImageModels,
SupportedImgSize,
SupportedModel,
} from '@configs';

export interface Message {
content: string;
Expand All @@ -25,7 +29,8 @@ export interface Conversation {
export interface GlobalConfig {
password: string;
openAIApiKey: string;
model: SupportedModel;
model: SupportedModel; // text model
imageModel: SupportedImageModels; // image model
save: boolean;
continuous: boolean;
messagesCount: number;
Expand Down
40 changes: 27 additions & 13 deletions src/modules/Configuration/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Divider, Input, Select, Slider, Switch, Tooltip } from 'antd';
import {
defaultConversation,
globalConfigLocalKey,
supportedImageModels,
supportedImgSizes,
supportedLanguages,
supportedModels,
Expand Down Expand Up @@ -160,21 +161,19 @@ const Configuration: FC<ConfigurationProps> = ({
<Divider className="!mt-6 !mb-6" orientation="left" plain>
{i18n.chat_mode_image}
</Divider>
<div className="mb-6">
<div className="mb-2">{i18n.config_images_count}</div>
<Slider
className="w-full"
min={1}
max={10}
step={1}
defaultValue={1}
value={configs.imagesCount}
onChange={(imagesCount) =>
updateConfigsAndStorages({ imagesCount })
}
<div className="flex items-center justify-between mb-6">
<div>{i18n.config_model}</div>
<Select
className="w-1/2"
value={configs.imageModel}
options={supportedImageModels.map((model) => ({
label: model,
value: model,
}))}
onChange={(imageModel) => updateConfigsAndStorages({ imageModel })}
/>
</div>
<div className="flex items-center justify-between">
<div className="flex items-center justify-between mb-6">
<div>{i18n.config_images_size}</div>
<Select
className="w-1/2"
Expand All @@ -186,6 +185,21 @@ const Configuration: FC<ConfigurationProps> = ({
onChange={(imageSize) => updateConfigsAndStorages({ imageSize })}
/>
</div>
<div>
<div className="mb-2">{i18n.config_images_count}</div>
<Slider
className="w-full"
disabled={configs.imageModel === 'Midjourney'}
min={1}
max={10}
step={1}
defaultValue={1}
value={configs.imagesCount}
onChange={(imagesCount) =>
updateConfigsAndStorages({ imagesCount })
}
/>
</div>
</div>
</div>
);
Expand Down
1 change: 1 addition & 0 deletions src/modules/Content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ const Content: FC<ContentProps> = ({ setActiveSetting }) => {
size: configs.imageSize || '256x256',
n: configs.imagesCount || 1,
password: configs.password,
model: configs.imageModel,
}),
});
const { data = [], msg } = await res.json();
Expand Down
18 changes: 17 additions & 1 deletion src/pages/api/images.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* eslint-disable no-console */
import type { APIRoute } from 'astro';
import { loadBalancer } from '@utils/server';
import { createOpenjourney } from 'replicate-fetch';
import { SupportedImageModels } from '@configs';
import { apiKeyStrategy, apiKeys, baseURL, config, password as pwd } from '.';

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

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

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

try {
if ((model as SupportedImageModels) === 'Midjourney') {
const len = size?.split('x')?.[0] ?? 256;
const data = await createOpenjourney({
prompt,
width: Number(len),
height: Number(len),
});
return new Response(
JSON.stringify({
data: data ?? [],
}),
{ status: 200 }
);
}
const image = await fetch(`https://${baseURL}/v1/images/generations`, {
headers: {
'Content-Type': 'application/json',
Expand Down

0 comments on commit 99ed02c

Please sign in to comment.