Skip to content

Commit

Permalink
Merge pull request ChatGPTNextWeb#882 from Yidadaa/bugfix-0417
Browse files Browse the repository at this point in the history
feat: user prompts
  • Loading branch information
Yidadaa committed Apr 17, 2023
2 parents 78c9e66 + 789a779 commit b7b16aa
Show file tree
Hide file tree
Showing 16 changed files with 321 additions and 55 deletions.
5 changes: 2 additions & 3 deletions app/components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -570,10 +570,9 @@ export function Chat(props: {
if (userIndex === null) return;

setIsLoading(true);
chatStore
.onUserInput(session.messages[userIndex].content)
.then(() => setIsLoading(false));
const content = session.messages[userIndex].content;
deleteMessage(userIndex);
chatStore.onUserInput(content).then(() => setIsLoading(false));
inputRef.current?.focus();
};

Expand Down
60 changes: 60 additions & 0 deletions app/components/settings.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,63 @@
min-width: 80%;
}
}

.user-prompt-modal {
min-height: 40vh;

.user-prompt-search {
width: 100%;
max-width: 100%;
margin-bottom: 10px;
background-color: var(--gray);
}

.user-prompt-list {
padding: 10px 0;

.user-prompt-item {
margin-bottom: 10px;
widows: 100%;

.user-prompt-header {
display: flex;
widows: 100%;
margin-bottom: 5px;

.user-prompt-title {
flex-grow: 1;
max-width: 100%;
margin-right: 5px;
padding: 5px;
font-size: 12px;
text-align: left;
}

.user-prompt-buttons {
display: flex;
align-items: center;

.user-prompt-button {
height: 100%;

&:not(:last-child) {
margin-right: 5px;
}
}
}
}

.user-prompt-content {
width: 100%;
box-sizing: border-box;
padding: 5px;
margin-right: 10px;
font-size: 12px;
flex-grow: 1;
}
}
}

.user-prompt-actions {
}
}
137 changes: 121 additions & 16 deletions app/components/settings.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { useState, useEffect, useMemo, HTMLProps } from "react";
import { useState, useEffect, useMemo, HTMLProps, useRef } from "react";

import EmojiPicker, { Theme as EmojiTheme } from "emoji-picker-react";

import styles from "./settings.module.scss";

import ResetIcon from "../icons/reload.svg";
import CloseIcon from "../icons/close.svg";
import CopyIcon from "../icons/copy.svg";
import ClearIcon from "../icons/clear.svg";
import EditIcon from "../icons/edit.svg";
import EyeIcon from "../icons/eye.svg";
import EyeOffIcon from "../icons/eye-off.svg";

import { List, ListItem, Popover, showToast } from "./ui-lib";
import { Input, List, ListItem, Modal, Popover } from "./ui-lib";

import { IconButton } from "./button";
import {
Expand All @@ -26,14 +27,114 @@ import {
import { Avatar } from "./chat";

import Locale, { AllLangs, changeLang, getLang } from "../locales";
import { getEmojiUrl } from "../utils";
import { copyToClipboard, getEmojiUrl } from "../utils";
import Link from "next/link";
import { UPDATE_URL } from "../constant";
import { SearchService, usePromptStore } from "../store/prompt";
import { requestUsage } from "../requests";
import { Prompt, SearchService, usePromptStore } from "../store/prompt";
import { ErrorBoundary } from "./error";
import { InputRange } from "./input-range";

function UserPromptModal(props: { onClose?: () => void }) {
const promptStore = usePromptStore();
const userPrompts = promptStore.getUserPrompts();
const builtinPrompts = SearchService.builtinPrompts;
const allPrompts = userPrompts.concat(builtinPrompts);
const [searchInput, setSearchInput] = useState("");
const [searchPrompts, setSearchPrompts] = useState<Prompt[]>([]);
const prompts = searchInput.length > 0 ? searchPrompts : allPrompts;

useEffect(() => {
if (searchInput.length > 0) {
const searchResult = SearchService.search(searchInput);
setSearchPrompts(searchResult);
} else {
setSearchPrompts([]);
}
}, [searchInput]);

return (
<div className="modal-mask">
<Modal
title={Locale.Settings.Prompt.Modal.Title}
onClose={() => props.onClose?.()}
actions={[
<IconButton
key="add"
onClick={() => promptStore.add({ title: "", content: "" })}
icon={<ClearIcon />}
bordered
text={Locale.Settings.Prompt.Modal.Add}
/>,
]}
>
<div className={styles["user-prompt-modal"]}>
<input
type="text"
className={styles["user-prompt-search"]}
placeholder={Locale.Settings.Prompt.Modal.Search}
value={searchInput}
onInput={(e) => setSearchInput(e.currentTarget.value)}
></input>

<div className={styles["user-prompt-list"]}>
{prompts.map((v, _) => (
<div className={styles["user-prompt-item"]} key={v.id ?? v.title}>
<div className={styles["user-prompt-header"]}>
<input
type="text"
className={styles["user-prompt-title"]}
value={v.title}
readOnly={!v.isUser}
onChange={(e) => {
if (v.isUser) {
promptStore.updateUserPrompts(
v.id!,
(prompt) => (prompt.title = e.currentTarget.value),
);
}
}}
></input>

<div className={styles["user-prompt-buttons"]}>
{v.isUser && (
<IconButton
icon={<ClearIcon />}
bordered
className={styles["user-prompt-button"]}
onClick={() => promptStore.remove(v.id!)}
/>
)}
<IconButton
icon={<CopyIcon />}
bordered
className={styles["user-prompt-button"]}
onClick={() => copyToClipboard(v.content)}
/>
</div>
</div>
<Input
rows={2}
value={v.content}
className={styles["user-prompt-content"]}
readOnly={!v.isUser}
onChange={(e) => {
if (v.isUser) {
promptStore.updateUserPrompts(
v.id!,
(prompt) => (prompt.content = e.currentTarget.value),
);
}
}}
/>
</div>
))}
</div>
</div>
</Modal>
</div>
);
}

function SettingItem(props: {
title: string;
subTitle?: string;
Expand Down Expand Up @@ -99,18 +200,16 @@ export function Settings(props: { closeSettings: () => void }) {
});
}

const [usage, setUsage] = useState<{
used?: number;
subscription?: number;
}>();
const usage = {
used: updateStore.used,
subscription: updateStore.subscription,
};
const [loadingUsage, setLoadingUsage] = useState(false);
function checkUsage() {
setLoadingUsage(true);
requestUsage()
.then((res) => setUsage(res))
.finally(() => {
setLoadingUsage(false);
});
updateStore.updateUsage().finally(() => {
setLoadingUsage(false);
});
}

const accessStore = useAccessStore();
Expand All @@ -122,10 +221,12 @@ export function Settings(props: { closeSettings: () => void }) {

const promptStore = usePromptStore();
const builtinCount = SearchService.count.builtin;
const customCount = promptStore.prompts.size ?? 0;
const customCount = promptStore.getUserPrompts().length ?? 0;
const [shouldShowPromptModal, setShowPromptModal] = useState(false);

const showUsage = accessStore.isAuthorized();
useEffect(() => {
// checks per minutes
checkUpdate();
showUsage && checkUsage();
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand Down Expand Up @@ -469,7 +570,7 @@ export function Settings(props: { closeSettings: () => void }) {
<IconButton
icon={<EditIcon />}
text={Locale.Settings.Prompt.Edit}
onClick={() => showToast(Locale.WIP)}
onClick={() => setShowPromptModal(true)}
/>
</SettingItem>
</List>
Expand Down Expand Up @@ -555,6 +656,10 @@ export function Settings(props: { closeSettings: () => void }) {
></InputRange>
</SettingItem>
</List>

{shouldShowPromptModal && (
<UserPromptModal onClose={() => setShowPromptModal(false)} />
)}
</div>
</ErrorBoundary>
);
Expand Down
2 changes: 1 addition & 1 deletion app/components/ui-lib.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
box-shadow: var(--card-shadow);
background-color: var(--white);
border-radius: 12px;
width: 50vw;
width: 60vw;
animation: slide-in ease 0.3s;

--modal-padding: 20px;
Expand Down
9 changes: 7 additions & 2 deletions app/locales/cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ const cn = {
ResetAll: "重置所有选项",
Close: "关闭",
ConfirmResetAll: {
Confirm: "Are you sure you want to reset all configurations?",
Confirm: "确认清除所有配置?",
},
ConfirmClearAll: {
Confirm: "Are you sure you want to reset all chat?",
Confirm: "确认清除所有聊天记录?",
},
},
Lang: {
Expand Down Expand Up @@ -105,6 +105,11 @@ const cn = {
ListCount: (builtin: number, custom: number) =>
`内置 ${builtin} 条,用户定义 ${custom} 条`,
Edit: "编辑",
Modal: {
Title: "提示词列表",
Add: "增加一条",
Search: "搜尋提示詞",
},
},
HistoryCount: {
Title: "附带历史消息数",
Expand Down
5 changes: 5 additions & 0 deletions app/locales/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ const de: LocaleType = {
ListCount: (builtin: number, custom: number) =>
`${builtin} integriert, ${custom} benutzerdefiniert`,
Edit: "Bearbeiten",
Modal: {
Title: "Prompt List",
Add: "Add One",
Search: "Search Prompts",
},
},
HistoryCount: {
Title: "Anzahl der angehängten Nachrichten",
Expand Down
7 changes: 6 additions & 1 deletion app/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ const en: LocaleType = {
ListCount: (builtin: number, custom: number) =>
`${builtin} built-in, ${custom} user-defined`,
Edit: "Edit",
Modal: {
Title: "Prompt List",
Add: "Add One",
Search: "Search Prompts",
},
},
HistoryCount: {
Title: "Attached Messages Count",
Expand All @@ -128,7 +133,7 @@ const en: LocaleType = {
return `Used this month $${used}, subscription $${total}`;
},
IsChecking: "Checking...",
Check: "Check Again",
Check: "Check",
NoAccess: "Enter API Key to check balance",
},
AccessCode: {
Expand Down
5 changes: 5 additions & 0 deletions app/locales/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ const es: LocaleType = {
ListCount: (builtin: number, custom: number) =>
`${builtin} incorporado, ${custom} definido por el usuario`,
Edit: "Editar",
Modal: {
Title: "Prompt List",
Add: "Add One",
Search: "Search Prompts",
},
},
HistoryCount: {
Title: "Cantidad de mensajes adjuntos",
Expand Down
5 changes: 5 additions & 0 deletions app/locales/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ const it: LocaleType = {
ListCount: (builtin: number, custom: number) =>
`${builtin} built-in, ${custom} user-defined`,
Edit: "Modifica",
Modal: {
Title: "Prompt List",
Add: "Add One",
Search: "Search Prompts",
},
},
HistoryCount: {
Title: "Conteggio dei messaggi allegati",
Expand Down
5 changes: 5 additions & 0 deletions app/locales/jp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ const jp = {
ListCount: (builtin: number, custom: number) =>
`組み込み ${builtin} 件、ユーザー定義 ${custom} 件`,
Edit: "編集",
Modal: {
Title: "提示词列表",
Add: "增加一条",
Search: "搜尋提示詞",
},
},
HistoryCount: {
Title: "履歴メッセージ数を添付",
Expand Down
5 changes: 5 additions & 0 deletions app/locales/tr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ const tr: LocaleType = {
ListCount: (builtin: number, custom: number) =>
`${builtin} yerleşik, ${custom} kullanıcı tanımlı`,
Edit: "Düzenle",
Modal: {
Title: "Prompt List",
Add: "Add One",
Search: "Search Prompts",
},
},
HistoryCount: {
Title: "Ekli Mesaj Sayısı",
Expand Down
Loading

0 comments on commit b7b16aa

Please sign in to comment.