Merge branch 'Yidadaa:main' into main

This commit is contained in:
AprilNEA
2023-03-30 16:02:42 +08:00
committed by GitHub
21 changed files with 372 additions and 150 deletions

View File

@@ -221,6 +221,14 @@
margin-bottom: 100px;
}
.chat-body-title {
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
.chat-message {
display: flex;
flex-direction: row;
@@ -410,7 +418,7 @@
background-color: var(--white);
color: var(--black);
font-family: inherit;
padding: 10px 14px;
padding: 10px 14px 50px;
resize: none;
outline: none;
}

View File

@@ -199,7 +199,10 @@ export function PromptHints(props: {
);
}
export function Chat(props: { showSideBar?: () => void }) {
export function Chat(props: {
showSideBar?: () => void;
sideBarShowing?: boolean;
}) {
type RenderMessage = Message & { preview?: boolean };
const chatStore = useChatStore();
@@ -219,7 +222,6 @@ export function Chat(props: { showSideBar?: () => void }) {
const [promptHints, setPromptHints] = useState<Prompt[]>([]);
const onSearch = useDebouncedCallback(
(text: string) => {
if (chatStore.config.disablePromptHint) return;
setPromptHints(promptStore.search(text));
},
100,
@@ -232,15 +234,31 @@ export function Chat(props: { showSideBar?: () => void }) {
inputRef.current?.focus();
};
const scrollInput = () => {
const dom = inputRef.current;
if (!dom) return;
const paddingBottomNum: number = parseInt(
window.getComputedStyle(dom).paddingBottom,
10
);
dom.scrollTop = dom.scrollHeight - dom.offsetHeight + paddingBottomNum;
};
// only search prompts when user input is short
const SEARCH_TEXT_LIMIT = 30;
const onInput = (text: string) => {
scrollInput();
setUserInput(text);
const n = text.trim().length;
if (n === 0 || n > SEARCH_TEXT_LIMIT) {
// clear search results
if (n === 0) {
setPromptHints([]);
} else {
onSearch(text);
} else if (!chatStore.config.disablePromptHint && n < SEARCH_TEXT_LIMIT) {
// check if need to trigger auto completion
if (text.startsWith("/") && text.length > 1) {
onSearch(text.slice(1));
}
}
};
@@ -250,6 +268,7 @@ export function Chat(props: { showSideBar?: () => void }) {
setIsLoading(true);
chatStore.onUserInput(userInput).then(() => setIsLoading(false));
setUserInput("");
setPromptHints([]);
inputRef.current?.focus();
};
@@ -286,6 +305,7 @@ export function Chat(props: { showSideBar?: () => void }) {
chatStore
.onUserInput(messages[i].content)
.then(() => setIsLoading(false));
inputRef.current?.focus();
return;
}
}
@@ -330,7 +350,6 @@ export function Chat(props: { showSideBar?: () => void }) {
const dom = latestMessageRef.current;
if (dom && !isIOS() && autoScroll) {
dom.scrollIntoView({
behavior: "smooth",
block: "end",
});
}
@@ -344,7 +363,17 @@ export function Chat(props: { showSideBar?: () => void }) {
className={styles["window-header-title"]}
onClick={props?.showSideBar}
>
<div className={styles["window-header-main-title"]}>
<div
className={`${styles["window-header-main-title"]} ${styles["chat-body-title"]}`}
onClick={() => {
const newTopic = prompt(Locale.Chat.Rename, session.topic);
if (newTopic && newTopic !== session.topic) {
chatStore.updateCurrentSession(
(session) => (session.topic = newTopic!)
);
}
}}
>
{session.topic}
</div>
<div className={styles["window-header-sub-title"]}>
@@ -439,6 +468,7 @@ export function Chat(props: { showSideBar?: () => void }) {
className="markdown-body"
style={{ fontSize: `${fontSize}px` }}
onContextMenu={(e) => onRightClick(e, message)}
onDoubleClickCapture={() => setUserInput(message.content)}
>
<Markdown content={message.content} />
</div>
@@ -455,7 +485,7 @@ export function Chat(props: { showSideBar?: () => void }) {
</div>
);
})}
<div ref={latestMessageRef} style={{ opacity: 0, height: "2em" }}>
<div ref={latestMessageRef} style={{ opacity: 0, height: "4em" }}>
-
</div>
</div>
@@ -476,7 +506,7 @@ export function Chat(props: { showSideBar?: () => void }) {
setAutoScroll(false);
setTimeout(() => setPromptHints([]), 100);
}}
autoFocus
autoFocus={!props?.sideBarShowing}
/>
<IconButton
icon={<SendWhiteIcon />}
@@ -678,7 +708,11 @@ export function Home() {
}}
/>
) : (
<Chat key="chat" showSideBar={() => setShowSideBar(true)} />
<Chat
key="chat"
showSideBar={() => setShowSideBar(true)}
sideBarShowing={showSideBar}
/>
)}
</div>
</div>

View File

@@ -1,6 +1,7 @@
import ReactMarkdown from "react-markdown";
import "katex/dist/katex.min.css";
import RemarkMath from "remark-math";
import RemarkBreaks from "remark-breaks";
import RehypeKatex from "rehype-katex";
import RemarkGfm from "remark-gfm";
import RehypePrsim from "rehype-prism-plus";
@@ -29,7 +30,7 @@ export function PreCode(props: { children: any }) {
export function Markdown(props: { content: string }) {
return (
<ReactMarkdown
remarkPlugins={[RemarkMath, RemarkGfm]}
remarkPlugins={[RemarkMath, RemarkGfm, RemarkBreaks]}
rehypePlugins={[RehypeKatex, [RehypePrsim, { ignoreMissing: true }]]}
components={{
pre: PreCode,

View File

@@ -27,6 +27,7 @@ import { getCurrentCommitId } from "../utils";
import Link from "next/link";
import { UPDATE_URL } from "../constant";
import { SearchService, usePromptStore } from "../store/prompt";
import { requestUsage } from "../requests";
function SettingItem(props: {
title: string;
@@ -54,7 +55,7 @@ export function Settings(props: { closeSettings: () => void }) {
state.updateConfig,
state.resetConfig,
state.clearAllData,
]
],
);
const updateStore = useUpdateStore();
@@ -70,14 +71,34 @@ export function Settings(props: { closeSettings: () => void }) {
});
}
const [usage, setUsage] = useState<{
granted?: number;
used?: number;
}>();
const [loadingUsage, setLoadingUsage] = useState(false);
function checkUsage() {
setLoadingUsage(true);
requestUsage()
.then((res) =>
setUsage({
granted: res?.total_granted,
used: res?.total_used,
}),
)
.finally(() => {
setLoadingUsage(false);
});
}
useEffect(() => {
checkUpdate();
checkUsage();
}, []);
const accessStore = useAccessStore();
const enabledAccessControl = useMemo(
() => accessStore.enabledAccessControl(),
[]
[],
);
const promptStore = usePromptStore();
@@ -179,7 +200,7 @@ export function Settings(props: { closeSettings: () => void }) {
onChange={(e) => {
updateConfig(
(config) =>
(config.submitKey = e.target.value as any as SubmitKey)
(config.submitKey = e.target.value as any as SubmitKey),
);
}}
>
@@ -199,7 +220,7 @@ export function Settings(props: { closeSettings: () => void }) {
value={config.theme}
onChange={(e) => {
updateConfig(
(config) => (config.theme = e.target.value as any as Theme)
(config) => (config.theme = e.target.value as any as Theme),
);
}}
>
@@ -232,7 +253,7 @@ export function Settings(props: { closeSettings: () => void }) {
>
<input
type="range"
title={config.fontSize.toString() + 'px'}
title={`${config.fontSize ?? 14}px`}
value={config.fontSize}
min="12"
max="18"
@@ -240,7 +261,7 @@ export function Settings(props: { closeSettings: () => void }) {
onChange={(e) =>
updateConfig(
(config) =>
(config.fontSize = Number.parseInt(e.currentTarget.value))
(config.fontSize = Number.parseInt(e.currentTarget.value)),
)
}
></input>
@@ -253,7 +274,7 @@ export function Settings(props: { closeSettings: () => void }) {
checked={config.tightBorder}
onChange={(e) =>
updateConfig(
(config) => (config.tightBorder = e.currentTarget.checked)
(config) => (config.tightBorder = e.currentTarget.checked),
)
}
></input>
@@ -271,7 +292,7 @@ export function Settings(props: { closeSettings: () => void }) {
onChange={(e) =>
updateConfig(
(config) =>
(config.disablePromptHint = e.currentTarget.checked)
(config.disablePromptHint = e.currentTarget.checked),
)
}
></input>
@@ -281,7 +302,7 @@ export function Settings(props: { closeSettings: () => void }) {
title={Locale.Settings.Prompt.List}
subTitle={Locale.Settings.Prompt.ListCount(
builtinCount,
customCount
customCount,
)}
>
<IconButton
@@ -324,6 +345,28 @@ export function Settings(props: { closeSettings: () => void }) {
></input>
</SettingItem>
<SettingItem
title={Locale.Settings.Usage.Title}
subTitle={
loadingUsage
? Locale.Settings.Usage.IsChecking
: Locale.Settings.Usage.SubTitle(
usage?.granted ?? "[?]",
usage?.used ?? "[?]",
)
}
>
{loadingUsage ? (
<div />
) : (
<IconButton
icon={<ResetIcon></ResetIcon>}
text={Locale.Settings.Usage.Check}
onClick={checkUsage}
/>
)}
</SettingItem>
<SettingItem
title={Locale.Settings.HistoryCount.Title}
subTitle={Locale.Settings.HistoryCount.SubTitle}
@@ -338,7 +381,7 @@ export function Settings(props: { closeSettings: () => void }) {
onChange={(e) =>
updateConfig(
(config) =>
(config.historyMessageCount = e.target.valueAsNumber)
(config.historyMessageCount = e.target.valueAsNumber),
)
}
></input>
@@ -357,7 +400,7 @@ export function Settings(props: { closeSettings: () => void }) {
updateConfig(
(config) =>
(config.compressMessageLengthThreshold =
e.currentTarget.valueAsNumber)
e.currentTarget.valueAsNumber),
)
}
></input>
@@ -370,7 +413,8 @@ export function Settings(props: { closeSettings: () => void }) {
value={config.modelConfig.model}
onChange={(e) => {
updateConfig(
(config) => (config.modelConfig.model = e.currentTarget.value)
(config) =>
(config.modelConfig.model = e.currentTarget.value),
);
}}
>
@@ -389,13 +433,13 @@ export function Settings(props: { closeSettings: () => void }) {
type="range"
value={config.modelConfig.temperature.toFixed(1)}
min="0"
max="1"
max="2"
step="0.1"
onChange={(e) => {
updateConfig(
(config) =>
(config.modelConfig.temperature =
e.currentTarget.valueAsNumber)
e.currentTarget.valueAsNumber),
);
}}
></input>
@@ -413,7 +457,7 @@ export function Settings(props: { closeSettings: () => void }) {
updateConfig(
(config) =>
(config.modelConfig.max_tokens =
e.currentTarget.valueAsNumber)
e.currentTarget.valueAsNumber),
)
}
></input>
@@ -432,7 +476,7 @@ export function Settings(props: { closeSettings: () => void }) {
updateConfig(
(config) =>
(config.modelConfig.presence_penalty =
e.currentTarget.valueAsNumber)
e.currentTarget.valueAsNumber),
);
}}
></input>