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

v2.0 Prompt Templates #993

Merged
merged 19 commits into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
feat: add mask page
  • Loading branch information
Yidadaa committed Apr 24, 2023
commit ffa73025716774b88c685ef21c6a2e6d137b597f
2 changes: 2 additions & 0 deletions app/api/openai/typing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ import type {

export type ChatRequest = CreateChatCompletionRequest;
export type ChatResponse = CreateChatCompletionResponse;

export type Updater<T> = (updater: (value: T) => void) => void;
17 changes: 11 additions & 6 deletions app/components/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import styles from "./button.module.scss";

export function IconButton(props: {
onClick?: () => void;
icon: JSX.Element;
icon?: JSX.Element;
text?: string;
bordered?: boolean;
shadow?: boolean;
Expand All @@ -26,11 +26,16 @@ export function IconButton(props: {
disabled={props.disabled}
role="button"
>
<div
className={styles["icon-button-icon"] + ` ${props.noDark && "no-dark"}`}
>
{props.icon}
</div>
{props.icon && (
<div
className={
styles["icon-button-icon"] + ` ${props.noDark && "no-dark"}`
}
>
{props.icon}
</div>
)}

{props.text && (
<div className={styles["icon-button-text"]}>{props.text}</div>
)}
Expand Down
203 changes: 36 additions & 167 deletions app/components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ import { useNavigate } from "react-router-dom";
import { Path } from "../constant";
import { ModelConfigList } from "./model-config";
import { Avatar, AvatarPicker } from "./emoji";
import { MaskConfig } from "./mask";
import { DEFAULT_MASK_ID } from "../store/mask";

const Markdown = dynamic(
async () => memo((await import("./markdown")).Markdown),
Expand Down Expand Up @@ -103,103 +105,10 @@ function exportMessages(messages: Message[], topic: string) {
});
}

function ContextPrompts() {
const chatStore = useChatStore();
const session = chatStore.currentSession();
const context = session.context;

const addContextPrompt = (prompt: Message) => {
chatStore.updateCurrentSession((session) => {
session.context.push(prompt);
});
};

const removeContextPrompt = (i: number) => {
chatStore.updateCurrentSession((session) => {
session.context.splice(i, 1);
});
};

const updateContextPrompt = (i: number, prompt: Message) => {
chatStore.updateCurrentSession((session) => {
session.context[i] = prompt;
});
};

return (
<>
<div className={chatStyle["context-prompt"]} style={{ marginBottom: 20 }}>
{context.map((c, i) => (
<div className={chatStyle["context-prompt-row"]} key={i}>
<select
value={c.role}
className={chatStyle["context-role"]}
onChange={(e) =>
updateContextPrompt(i, {
...c,
role: e.target.value as any,
})
}
>
{ROLES.map((r) => (
<option key={r} value={r}>
{r}
</option>
))}
</select>
<Input
value={c.content}
type="text"
className={chatStyle["context-content"]}
rows={1}
onInput={(e) =>
updateContextPrompt(i, {
...c,
content: e.currentTarget.value as any,
})
}
/>
<IconButton
icon={<DeleteIcon />}
className={chatStyle["context-delete-button"]}
onClick={() => removeContextPrompt(i)}
bordered
/>
</div>
))}

<div className={chatStyle["context-prompt-row"]}>
<IconButton
icon={<AddIcon />}
text={Locale.Context.Add}
bordered
className={chatStyle["context-prompt-button"]}
onClick={() =>
addContextPrompt({
role: "system",
content: "",
date: "",
})
}
/>
</div>
</div>
</>
);
}

export function SessionConfigModel(props: { onClose: () => void }) {
const chatStore = useChatStore();
const session = chatStore.currentSession();

const [showPicker, setShowPicker] = useState(false);

const updateConfig = (updater: (config: ModelConfig) => void) => {
const config = { ...session.modelConfig };
updater(config);
chatStore.updateCurrentSession((session) => (session.modelConfig = config));
};

return (
<div className="modal-mask">
<Modal
Expand All @@ -210,7 +119,7 @@ export function SessionConfigModel(props: { onClose: () => void }) {
key="reset"
icon={<CopyIcon />}
bordered
text="重置预设"
text="重置"
onClick={() =>
confirm(Locale.Memory.ResetConfirm) && chatStore.resetSession()
}
Expand All @@ -219,69 +128,29 @@ export function SessionConfigModel(props: { onClose: () => void }) {
key="copy"
icon={<CopyIcon />}
bordered
text="保存预设"
text="保存为面具"
onClick={() => copyToClipboard(session.memoryPrompt)}
/>,
]}
>
<ContextPrompts />

<List>
<ListItem title={"角色头像"}>
<Popover
content={
<AvatarPicker
onEmojiClick={(emoji) =>
chatStore.updateCurrentSession(
(session) => (session.avatar = emoji),
)
}
></AvatarPicker>
}
open={showPicker}
onClose={() => setShowPicker(false)}
>
<div
onClick={() => setShowPicker(true)}
style={{ cursor: "pointer" }}
>
{session.avatar ? (
<Avatar avatar={session.avatar} />
) : (
<Avatar model={session.modelConfig.model} />
)}
</div>
</Popover>
</ListItem>
<ListItem title={"对话标题"}>
<input
type="text"
value={session.topic}
onInput={(e) =>
chatStore.updateCurrentSession(
(session) => (session.topic = e.currentTarget.value),
)
}
></input>
</ListItem>
</List>

<List>
<ModelConfigList
modelConfig={session.modelConfig}
updateConfig={updateConfig}
/>

{session.modelConfig.sendMemory ? (
<ListItem
title={`${Locale.Memory.Title} (${session.lastSummarizeIndex} of
${session.messages.length})`}
subTitle={session.memoryPrompt || Locale.Memory.EmptyContent}
></ListItem>
) : (
<></>
)}
</List>
<MaskConfig
mask={session.mask}
updateMask={(updater) => {
const mask = { ...session.mask };
updater(mask);
chatStore.updateCurrentSession((session) => (session.mask = mask));
}}
extraListItems={
session.mask.modelConfig.sendMemory ? (
<ListItem
title={`${Locale.Memory.Title} (${session.lastSummarizeIndex} of ${session.messages.length})`}
subTitle={session.memoryPrompt || Locale.Memory.EmptyContent}
></ListItem>
) : (
<></>
)
}
></MaskConfig>
</Modal>
</div>
);
Expand All @@ -294,7 +163,7 @@ function PromptToast(props: {
}) {
const chatStore = useChatStore();
const session = chatStore.currentSession();
const context = session.context;
const context = session.mask.context;

return (
<div className={chatStyle["prompt-toast"]} key="prompt-toast">
Expand Down Expand Up @@ -617,7 +486,7 @@ export function Chat() {
inputRef.current?.focus();
};

const context: RenderMessage[] = session.context.slice();
const context: RenderMessage[] = session.mask.context.slice();

const accessStore = useAccessStore();

Expand Down Expand Up @@ -680,35 +549,35 @@ export function Chat() {

return (
<div className={styles.chat} key={session.id}>
<div className={styles["window-header"]}>
<div className={styles["window-header-title"]}>
<div className="window-header">
<div className="window-header-title">
<div
className={`${styles["window-header-main-title"]} ${styles["chat-body-title"]}`}
className={`window-header-main-title " ${styles["chat-body-title"]}`}
onClickCapture={renameSession}
>
{!session.topic ? DEFAULT_TOPIC : session.topic}
</div>
<div className={styles["window-header-sub-title"]}>
<div className="window-header-sub-title">
{Locale.Chat.SubTitle(session.messages.length)}
</div>
</div>
<div className={styles["window-actions"]}>
<div className={styles["window-action-button"] + " " + styles.mobile}>
<div className="window-actions">
<div className={"window-action-button" + " " + styles.mobile}>
<IconButton
icon={<ReturnIcon />}
bordered
title={Locale.Chat.Actions.ChatList}
onClick={() => navigate(Path.Home)}
/>
</div>
<div className={styles["window-action-button"]}>
<div className="window-action-button">
<IconButton
icon={<RenameIcon />}
bordered
onClick={renameSession}
/>
</div>
<div className={styles["window-action-button"]}>
<div className="window-action-button">
<IconButton
icon={<ExportIcon />}
bordered
Expand All @@ -722,7 +591,7 @@ export function Chat() {
/>
</div>
{!isMobileScreen && (
<div className={styles["window-action-button"]}>
<div className="window-action-button">
<IconButton
icon={config.tightBorder ? <MinIcon /> : <MaxIcon />}
bordered
Expand Down Expand Up @@ -773,10 +642,10 @@ export function Chat() {
<div className={styles["chat-message-avatar"]}>
{message.role === "user" ? (
<Avatar avatar={config.avatar} />
) : session.avatar ? (
<Avatar avatar={session.avatar} />
) : (
) : session.mask.id === DEFAULT_MASK_ID ? (
<Avatar model={message.model ?? "gpt-3.5-turbo"} />
) : (
<Avatar avatar={session.mask.avatar} />
)}
</div>
{showTyping && (
Expand Down
3 changes: 0 additions & 3 deletions app/components/home.module.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
@import "./window.scss";
@import "../styles/animation.scss";

@mixin container {
background-color: var(--white);
border: var(--border-in-light);
Expand Down
5 changes: 5 additions & 0 deletions app/components/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ const NewChat = dynamic(async () => (await import("./new-chat")).NewChat, {
loading: () => <Loading noLogo />,
});

const MaskPage = dynamic(async () => (await import("./mask")).MaskPage, {
loading: () => <Loading noLogo />,
});

export function useSwitchTheme() {
const config = useAppConfig();

Expand Down Expand Up @@ -109,6 +113,7 @@ function Screen() {
<Routes>
<Route path={Path.Home} element={<Chat />} />
<Route path={Path.NewChat} element={<NewChat />} />
<Route path={Path.Masks} element={<MaskPage />} />
<Route path={Path.Chat} element={<Chat />} />
<Route path={Path.Settings} element={<Settings />} />
</Routes>
Expand Down
33 changes: 33 additions & 0 deletions app/components/mask.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.mask-page {
height: 100%;
display: flex;
flex-direction: column;

.mask-page-body {
padding: 20px;
overflow-y: auto;

.search-bar {
width: 100%;
max-width: 100%;
margin-bottom: 20px;
}

.mask-item {
.mask-icon {
display: flex;
align-items: center;
justify-content: center;
border: var(--border-in-light);
border-radius: 10px;
padding: 6px;
}

.mask-actions {
display: flex;
flex-wrap: nowrap;
transition: all ease 0.3s;
}
}
}
}
Loading