Merge remote-tracking branch 'upstream/main'

This commit is contained in:
DirkSchlossmacher
2024-08-05 21:06:51 +02:00
51 changed files with 841 additions and 280 deletions

View File

@@ -37,6 +37,7 @@ import AutoIcon from "../icons/auto.svg";
import BottomIcon from "../icons/bottom.svg";
import StopIcon from "../icons/pause.svg";
import RobotIcon from "../icons/robot.svg";
import SizeIcon from "../icons/size.svg";
import PluginIcon from "../icons/plugin.svg";
import {
@@ -60,6 +61,7 @@ import {
getMessageTextContent,
getMessageImages,
isVisionModel,
isDalle3,
} from "../utils";
import { uploadImage as uploadImageRemote } from "@/app/utils/chat";
@@ -67,6 +69,7 @@ import { uploadImage as uploadImageRemote } from "@/app/utils/chat";
import dynamic from "next/dynamic";
import { ChatControllerPool } from "../client/controller";
import { DalleSize } from "../typing";
import { Prompt, usePromptStore } from "../store/prompt";
import Locale from "../locales";
@@ -481,6 +484,11 @@ export function ChatActions(props: {
const [showPluginSelector, setShowPluginSelector] = useState(false);
const [showUploadImage, setShowUploadImage] = useState(false);
const [showSizeSelector, setShowSizeSelector] = useState(false);
const dalle3Sizes: DalleSize[] = ["1024x1024", "1792x1024", "1024x1792"];
const currentSize =
chatStore.currentSession().mask.modelConfig?.size ?? "1024x1024";
useEffect(() => {
const show = isVisionModel(currentModel);
setShowUploadImage(show);
@@ -624,6 +632,33 @@ export function ChatActions(props: {
/>
)}
{isDalle3(currentModel) && (
<ChatAction
onClick={() => setShowSizeSelector(true)}
text={currentSize}
icon={<SizeIcon />}
/>
)}
{showSizeSelector && (
<Selector
defaultSelectedValue={currentSize}
items={dalle3Sizes.map((m) => ({
title: m,
value: m,
}))}
onClose={() => setShowSizeSelector(false)}
onSelection={(s) => {
if (s.length === 0) return;
const size = s[0];
chatStore.updateCurrentSession((session) => {
session.mask.modelConfig.size = size;
});
showToast(size);
}}
/>
)}
<ChatAction
onClick={() => setShowPluginSelector(true)}
text={Locale.Plugin.Name}
@@ -732,6 +767,7 @@ function _Chat() {
const session = chatStore.currentSession();
const config = useAppConfig();
const fontSize = config.fontSize;
const fontFamily = config.fontFamily;
const [showExport, setShowExport] = useState(false);
@@ -811,7 +847,7 @@ function _Chat() {
// clear search results
if (n === 0) {
setPromptHints([]);
} else if (text.startsWith(ChatCommandPrefix)) {
} else if (text.match(ChatCommandPrefix)) {
setPromptHints(chatCommands.search(text));
} else if (!config.disablePromptHint && n < SEARCH_TEXT_LIMIT) {
// check if need to trigger auto completion
@@ -1482,6 +1518,7 @@ function _Chat() {
setUserInput(getMessageTextContent(message));
}}
fontSize={fontSize}
fontFamily={fontFamily}
parentRef={scrollRef}
defaultShow={i >= messages.length - 6}
/>
@@ -1576,6 +1613,7 @@ function _Chat() {
autoFocus={autoFocus}
style={{
fontSize: config.fontSize,
fontFamily: config.fontFamily,
}}
/>
{attachImages.length != 0 && (

View File

@@ -583,6 +583,7 @@ export function ImagePreviewer(props: {
<Markdown
content={getMessageTextContent(m)}
fontSize={config.fontSize}
fontFamily={config.fontFamily}
defaultShow
/>
{getMessageImages(m).length == 1 && (

View File

@@ -137,12 +137,18 @@
position: relative;
padding-top: 20px;
padding-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.sidebar-logo {
position: absolute;
right: 0;
bottom: 18px;
display: inline-flex;
}
.sidebar-title-container {
display: inline-flex;
flex-direction: column;
}
.sidebar-title {

View File

@@ -96,6 +96,32 @@ export function PreCode(props: { children: any }) {
[plugins],
);
//Wrap the paragraph for plain-text
useEffect(() => {
if (ref.current) {
const codeElements = ref.current.querySelectorAll(
"code",
) as NodeListOf<HTMLElement>;
const wrapLanguages = [
"",
"md",
"markdown",
"text",
"txt",
"plaintext",
"tex",
"latex",
];
codeElements.forEach((codeElement) => {
let languageClass = codeElement.className.match(/language-(\w+)/);
let name = languageClass ? languageClass[1] : "";
if (wrapLanguages.includes(name)) {
codeElement.style.whiteSpace = "pre-wrap";
}
});
}
}, []);
return (
<>
<pre ref={ref}>
@@ -206,6 +232,7 @@ export function Markdown(
content: string;
loading?: boolean;
fontSize?: number;
fontFamily?: string;
parentRef?: RefObject<HTMLDivElement>;
defaultShow?: boolean;
} & React.DOMAttributes<HTMLDivElement>,
@@ -217,6 +244,7 @@ export function Markdown(
className="markdown-body"
style={{
fontSize: `${props.fontSize ?? 14}px`,
fontFamily: props.fontFamily || "inherit",
}}
ref={mdRef}
onContextMenu={props.onContextMenu}

View File

@@ -23,7 +23,6 @@ import CopyIcon from "@/app/icons/copy.svg";
import PromptIcon from "@/app/icons/prompt.svg";
import ResetIcon from "@/app/icons/reload.svg";
import { useSdStore } from "@/app/store/sd";
import locales from "@/app/locales";
import LoadingIcon from "@/app/icons/three-dots.svg";
import ErrorIcon from "@/app/icons/delete.svg";
import SDIcon from "@/app/icons/sd.svg";
@@ -64,14 +63,14 @@ function getSdTaskStatus(item: any) {
return (
<p className={styles["line-1"]} title={item.error} style={{ color: color }}>
<span>
{locales.Sd.Status.Name}: {s}
{Locale.Sd.Status.Name}: {s}
</span>
{item.status === "error" && (
<span
className="clickable"
onClick={() => {
showModal({
title: locales.Sd.Detail,
title: Locale.Sd.Detail,
children: (
<div style={{ color: color, userSelect: "text" }}>
{item.error}
@@ -189,13 +188,13 @@ export function Sd() {
className={styles["sd-img-item-info"]}
>
<p className={styles["line-1"]}>
{locales.SdPanel.Prompt}:{" "}
{Locale.SdPanel.Prompt}:{" "}
<span
className="clickable"
title={item.params.prompt}
onClick={() => {
showModal({
title: locales.Sd.Detail,
title: Locale.Sd.Detail,
children: (
<div style={{ userSelect: "text" }}>
{item.params.prompt}
@@ -208,7 +207,7 @@ export function Sd() {
</span>
</p>
<p>
{locales.SdPanel.AIModel}: {item.model_name}
{Locale.SdPanel.AIModel}: {item.model_name}
</p>
{getSdTaskStatus(item)}
<p>{item.created_at}</p>
@@ -219,7 +218,7 @@ export function Sd() {
icon={<PromptIcon />}
onClick={() => {
showModal({
title: locales.Sd.GenerateParams,
title: Locale.Sd.GenerateParams,
children: (
<div style={{ userSelect: "text" }}>
{Object.keys(item.params).map((key) => {
@@ -325,7 +324,7 @@ export function Sd() {
);
})
) : (
<div>{locales.Sd.EmptyRecord}</div>
<div>{Locale.Sd.EmptyRecord}</div>
)}
</div>
</div>

View File

@@ -1316,6 +1316,22 @@ export function Settings() {
></InputRange>
</ListItem>
<ListItem
title={Locale.Settings.FontFamily.Title}
subTitle={Locale.Settings.FontFamily.SubTitle}
>
<input
type="text"
value={config.fontFamily}
placeholder={Locale.Settings.FontFamily.Placeholder}
onChange={(e) =>
updateConfig(
(config) => (config.fontFamily = e.currentTarget.value),
)
}
></input>
</ListItem>
<ListItem
title={Locale.Settings.AutoGenerateTitle.Title}
subTitle={Locale.Settings.AutoGenerateTitle.SubTitle}

View File

@@ -174,10 +174,12 @@ export function SideBarHeader(props: {
return (
<Fragment>
<div className={styles["sidebar-header"]} data-tauri-drag-region>
<div className={styles["sidebar-title"]} data-tauri-drag-region>
{title}
<div className={styles["sidebar-title-container"]}>
<div className={styles["sidebar-title"]} data-tauri-drag-region>
{title}
</div>
<div className={styles["sidebar-sub-title"]}>{subTitle}</div>
</div>
<div className={styles["sidebar-sub-title"]}>{subTitle}</div>
<div className={styles["sidebar-logo"] + " no-dark"}>{logo}</div>
</div>
{children}