Skip to content

Commit

Permalink
Merge pull request #40 from animalnots/feature/parse-models-from-open…
Browse files Browse the repository at this point in the history
…router

Added support for models parsing based on openrouter API
  • Loading branch information
animalnots authored Aug 15, 2024
2 parents ce3a542 + 787a566 commit c22e855
Show file tree
Hide file tree
Showing 25 changed files with 696 additions and 273 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,21 @@ If you would like to support the team, consider sponsoring us through one of the
| Wechat (Ayaka) | <img src="https://ayaka14732.github.io/sponsor/wechat.png" width=150 /> |

Thank you for being a part of our community, and we look forward to serving you better in the future.

# Adding new settings
Example of files that had to be changed in order for a new settings to be added (e.g. ImageDetail for each chat + default config)
```plaintext
- public/locales/en/main.json
- public/locales/en/model.json
- src/assets/icons/AttachmentIcon.tsx
- src/components/Chat/ChatContent/ChatTitle.tsx
- src/components/Chat/ChatContent/Message/EditView.tsx
- src/components/ChatConfigMenu/ChatConfigMenu.tsx
- src/components/ConfigMenu/ConfigMenu.tsx
- src/constants/chat.ts
- src/store/config-slice.ts
- src/store/migrate.ts
- src/store/store.ts
- src/types/chat.ts
- src/utils/import.ts
```
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "better-chatgpt",
"private": true,
"version": "1.5.0",
"version": "1.6.0",
"type": "module",
"homepage": "./",
"main": "electron/index.cjs",
Expand Down Expand Up @@ -89,6 +89,7 @@
"react-i18next": "^12.2.0",
"react-markdown": "^8.0.5",
"react-scroll-to-bottom": "^4.2.0",
"react-select": "^5.8.0",
"react-toastify": "^10.0.5",
"rehype-highlight": "^6.0.0",
"rehype-katex": "^6.0.2",
Expand Down
1 change: 1 addition & 0 deletions public/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"resetCost": "Reset Costs",
"countTotalTokens": "Count total tokens",
"displayChatSize": "Display chat size in title",
"defaultImageDetail": "Image detail (auto, high, low resolution)",
"morePrompts": "You can find more prompts here: ",
"clearPrompts": "Clear prompts",
"postOnShareGPT": {
Expand Down
8 changes: 7 additions & 1 deletion public/locales/en/model.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,11 @@
},
"defaultChatConfig": "Default Chat Config",
"defaultSystemMessage": "Default System Message",
"resetToDefault": "Reset To Default"
"resetToDefault": "Reset To Default",
"imageDetail": {
"label": "Image Detail",
"low": "low",
"high": "high",
"auto": "auto"
}
}
3 changes: 1 addition & 2 deletions src/api/api.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { ShareGPTSubmitBodyInterface } from '@type/api';
import {
ConfigInterface,
ImageContentInterface,
MessageInterface,
ModelOptions,
} from '@type/chat';
import { isAzureEndpoint } from '@utils/api';
import { ModelOptions } from '@utils/modelReader';

export const getChatCompletion = async (
endpoint: string,
Expand Down
4 changes: 2 additions & 2 deletions src/assets/icons/AttachmentIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ const AttachmentIcon = () => {
>
<path
fill='currentColor'
fill-rule='evenodd'
fillRule='evenodd'
d='M9 7a5 5 0 0 1 10 0v8a7 7 0 1 1-14 0V9a1 1 0 0 1 2 0v6a5 5 0 0 0 10 0V7a3 3 0 1 0-6 0v8a1 1 0 1 0 2 0V9a1 1 0 1 1 2 0v6a3 3 0 1 1-6 0z'
clip-rule='evenodd'
clipRule='evenodd'
></path>
</svg>
);
Expand Down
39 changes: 26 additions & 13 deletions src/components/Chat/ChatContent/ChatTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ import { useTranslation } from 'react-i18next';
import { shallow } from 'zustand/shallow';
import useStore from '@store/store';
import ConfigMenu from '@components/ConfigMenu';
import { ChatInterface, ConfigInterface } from '@type/chat';
import { ChatInterface, ConfigInterface, ImageDetail } from '@type/chat';
import { _defaultChatConfig } from '@constants/chat';

const ChatTitle = React.memo(() => {
const { t } = useTranslation('model');
const config = useStore(
const chat = useStore(
(state) =>
state.chats &&
state.chats.length > 0 &&
state.currentChatIndex >= 0 &&
state.currentChatIndex < state.chats.length
? state.chats[state.currentChatIndex].config
? state.chats[state.currentChatIndex]
: undefined,
shallow
);
Expand All @@ -30,17 +30,25 @@ const ChatTitle = React.memo(() => {
setChats(updatedChats);
};

const setImageDetail = (imageDetail: ImageDetail) => {
const updatedChats: ChatInterface[] = JSON.parse(
JSON.stringify(useStore.getState().chats)
);
updatedChats[currentChatIndex].imageDetail = imageDetail;
setChats(updatedChats);
};

// for migrating from old ChatInterface to new ChatInterface (with config)
useEffect(() => {
const chats = useStore.getState().chats;
if (chats && chats.length > 0 && currentChatIndex !== -1 && !config) {
if (chats && chats.length > 0 && currentChatIndex !== -1 && !chat?.config) {
const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats));
updatedChats[currentChatIndex].config = { ..._defaultChatConfig };
setChats(updatedChats);
}
}, [currentChatIndex]);

return config ? (
return chat ? (
<>
<div
className='sticky top-0 z-10 flex gap-x-4 gap-y-1 flex-wrap w-full items-center justify-center border-b border-black/10 bg-gray-50 p-3 dark:border-gray-900/50 dark:bg-gray-700 text-gray-600 dark:text-gray-300 cursor-pointer'
Expand All @@ -49,29 +57,34 @@ const ChatTitle = React.memo(() => {
}}
>
<div className='text-center p-1 rounded-md bg-gray-300/20 dark:bg-gray-900/10 hover:bg-gray-300/50 dark:hover:bg-gray-900/50'>
{t('model')}: {config.model}
{t('model')}: {chat.config.model}
</div>
<div className='text-center p-1 rounded-md bg-gray-300/20 dark:bg-gray-900/10 hover:bg-gray-300/50 dark:hover:bg-gray-900/50'>
{t('token.label')}: {chat.config.max_tokens}
</div>
<div className='text-center p-1 rounded-md bg-gray-300/20 dark:bg-gray-900/10 hover:bg-gray-300/50 dark:hover:bg-gray-900/50'>
{t('token.label')}: {config.max_tokens}
{t('temperature.label')}: {chat.config.temperature}
</div>
<div className='text-center p-1 rounded-md bg-gray-300/20 dark:bg-gray-900/10 hover:bg-gray-300/50 dark:hover:bg-gray-900/50'>
{t('temperature.label')}: {config.temperature}
{t('topP.label')}: {chat.config.top_p}
</div>
<div className='text-center p-1 rounded-md bg-gray-300/20 dark:bg-gray-900/10 hover:bg-gray-300/50 dark:hover:bg-gray-900/50'>
{t('topP.label')}: {config.top_p}
{t('presencePenalty.label')}: {chat.config.presence_penalty}
</div>
<div className='text-center p-1 rounded-md bg-gray-300/20 dark:bg-gray-900/10 hover:bg-gray-300/50 dark:hover:bg-gray-900/50'>
{t('presencePenalty.label')}: {config.presence_penalty}
{t('frequencyPenalty.label')}: {chat.config.frequency_penalty}
</div>
<div className='text-center p-1 rounded-md bg-gray-300/20 dark:bg-gray-900/10 hover:bg-gray-300/50 dark:hover:bg-gray-900/50'>
{t('frequencyPenalty.label')}: {config.frequency_penalty}
{t('imageDetail.label')}: {chat.imageDetail}
</div>
</div>
{isModalOpen && (
<ConfigMenu
setIsModalOpen={setIsModalOpen}
config={config}
config={chat.config}
setConfig={setConfig}
imageDetail={chat.imageDetail}
setImageDetail={setImageDetail}
/>
)}
</>
Expand All @@ -80,4 +93,4 @@ const ChatTitle = React.memo(() => {
);
});

export default ChatTitle;
export default ChatTitle;
49 changes: 34 additions & 15 deletions src/components/Chat/ChatContent/Message/View/EditView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ import {
ChatInterface,
ContentInterface,
ImageContentInterface,
ModelOptions,
TextContentInterface,
} from '@type/chat';

import PopupModal from '@components/PopupModal';
import TokenCount from '@components/TokenCount';
import CommandPrompt from '../CommandPrompt';
import { defaultModel, modelTypes } from '@constants/chat';
import { defaultModel } from '@constants/chat';
import AttachmentIcon from '@icon/AttachmentIcon';
import { ModelOptions } from '@utils/modelReader';
import { modelTypes } from '@constants/modelLoader';

const EditView = ({
content: content,
Expand Down Expand Up @@ -97,6 +98,10 @@ const EditView = ({
};

const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const updatedChats: ChatInterface[] = JSON.parse(
JSON.stringify(useStore.getState().chats)
);
const chat = updatedChats[currentChatIndex];
const files = e.target.files!;
const newImageURLs = Array.from(files).map((file: Blob) =>
URL.createObjectURL(file)
Expand All @@ -107,7 +112,7 @@ const EditView = ({
return {
type: 'image_url',
image_url: {
detail: 'auto',
detail: chat.imageDetail,
url: (await blobToBase64(blob)) as string,
},
} as ImageContentInterface;
Expand All @@ -120,11 +125,14 @@ const EditView = ({

const handleImageUrlChange = () => {
if (imageUrl.trim() === '') return;

const updatedChats: ChatInterface[] = JSON.parse(
JSON.stringify(useStore.getState().chats)
);
const chat = updatedChats[currentChatIndex];
const newImage: ImageContentInterface = {
type: 'image_url',
image_url: {
detail: 'auto',
detail: chat.imageDetail,
url: imageUrl,
},
};
Expand All @@ -148,12 +156,13 @@ const EditView = ({
};

const handleSave = () => {
if (
sticky &&
((_content[0] as TextContentInterface).text === '' ||
useStore.getState().generating)
)
const hasTextContent = (_content[0] as TextContentInterface).text !== '';
const hasImageContent = _content.some(content => content.type === 'image_url');

if (sticky && (!hasTextContent && !hasImageContent || useStore.getState().generating)) {
return;
}

const updatedChats: ChatInterface[] = JSON.parse(
JSON.stringify(useStore.getState().chats)
);
Expand All @@ -177,14 +186,20 @@ const EditView = ({

const { handleSubmit } = useSubmit();
const handleGenerate = () => {
if (useStore.getState().generating) return;
const hasTextContent = (_content[0] as TextContentInterface).text !== '';
const hasImageContent = _content.some(content => content.type === 'image_url');

if (!hasTextContent && !hasImageContent || useStore.getState().generating) {
return;
}

const updatedChats: ChatInterface[] = JSON.parse(
JSON.stringify(useStore.getState().chats)
);
const updatedMessages = updatedChats[currentChatIndex].messages;

if (sticky) {
if ((_content[0] as TextContentInterface).text !== '') {
if (hasTextContent || hasImageContent) {
updatedMessages.push({ role: inputRole, content: _content });
}
_setContent([
Expand Down Expand Up @@ -212,6 +227,10 @@ const EditView = ({

const handlePaste = async (e: React.ClipboardEvent<HTMLTextAreaElement>) => {
const items = e.clipboardData.items;
const updatedChats: ChatInterface[] = JSON.parse(
JSON.stringify(useStore.getState().chats)
);
const chat = updatedChats[currentChatIndex];
for (const item of items) {
if (item.type.startsWith('image/')) {
const blob = item.getAsFile();
Expand All @@ -220,7 +239,7 @@ const EditView = ({
const newImage: ImageContentInterface = {
type: 'image_url',
image_url: {
detail: 'auto',
detail: chat.imageDetail,
url: base64Image,
},
};
Expand Down Expand Up @@ -492,4 +511,4 @@ const EditViewButtons = memo(
}
);

export default EditView;
export default EditView;
Loading

0 comments on commit c22e855

Please sign in to comment.