Merge remote-tracking branch 'upstream/main' into dev

# Conflicts:
#	app/components/settings.tsx
#	app/components/sidebar.tsx
This commit is contained in:
sijinhui 2024-08-13 18:24:57 +08:00
commit 0b930db371
19 changed files with 219 additions and 31 deletions

View File

@ -51,6 +51,8 @@ export interface LLMConfig {
presence_penalty?: number; presence_penalty?: number;
frequency_penalty?: number; frequency_penalty?: number;
size?: DalleRequestPayload["size"]; size?: DalleRequestPayload["size"];
quality?: DalleRequestPayload["quality"];
style?: DalleRequestPayload["style"];
} }
export interface ChatOptions { export interface ChatOptions {

View File

@ -18,7 +18,7 @@ import {
base64Image2Blob, base64Image2Blob,
} from "@/app/utils/chat"; } from "@/app/utils/chat";
import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare"; import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare";
import { DalleSize } from "@/app/typing"; import { DalleSize, DalleQuality, DalleStyle } from "@/app/typing";
import { import {
ChatOptions, ChatOptions,
@ -71,6 +71,8 @@ export interface DalleRequestPayload {
response_format: "url" | "b64_json"; response_format: "url" | "b64_json";
n: number; n: number;
size: DalleSize; size: DalleSize;
quality: DalleQuality;
style: DalleStyle;
} }
export class ChatGPTApi implements LLMApi { export class ChatGPTApi implements LLMApi {
@ -163,6 +165,8 @@ export class ChatGPTApi implements LLMApi {
response_format: "b64_json", // using b64_json, and save image in CacheStorage response_format: "b64_json", // using b64_json, and save image in CacheStorage
n: 1, n: 1,
size: options.config?.size ?? "1024x1024", size: options.config?.size ?? "1024x1024",
quality: options.config?.quality ?? "standard",
style: options.config?.style ?? "vivid",
}; };
} else { } else {
const visionModel = isVisionModel(options.config.model); const visionModel = isVisionModel(options.config.model);

View File

@ -18,6 +18,7 @@ export function IconButton(props: {
tabIndex?: number; tabIndex?: number;
autoFocus?: boolean; autoFocus?: boolean;
style?: CSSProperties; style?: CSSProperties;
aria?: string;
}) { }) {
return ( return (
<button <button
@ -34,9 +35,11 @@ export function IconButton(props: {
tabIndex={props.tabIndex} tabIndex={props.tabIndex}
autoFocus={props.autoFocus} autoFocus={props.autoFocus}
style={props.style} style={props.style}
aria-label={props.aria}
> >
{props.icon && ( {props.icon && (
<div <div
aria-label={props.text || props.title}
className={ className={
styles["icon-button-icon"] + styles["icon-button-icon"] +
` ${props.type === "primary" && "no-dark"}` ` ${props.type === "primary" && "no-dark"}`
@ -47,7 +50,12 @@ export function IconButton(props: {
)} )}
{props.text && ( {props.text && (
<div className={styles["icon-button-text"]}>{props.text}</div> <div
aria-label={props.text || props.title}
className={styles["icon-button-text"]}
>
{props.text}
</div>
)} )}
</button> </button>
); );

View File

@ -38,6 +38,8 @@ import BottomIcon from "../icons/bottom.svg";
import StopIcon from "../icons/pause.svg"; import StopIcon from "../icons/pause.svg";
import RobotIcon from "../icons/robot.svg"; import RobotIcon from "../icons/robot.svg";
import SizeIcon from "../icons/size.svg"; import SizeIcon from "../icons/size.svg";
import QualityIcon from "../icons/hd.svg";
import StyleIcon from "../icons/palette.svg";
import PluginIcon from "../icons/plugin.svg"; import PluginIcon from "../icons/plugin.svg";
// import UploadIcon from "../icons/upload.svg"; // import UploadIcon from "../icons/upload.svg";
@ -72,7 +74,7 @@ import { uploadImage as uploadImageRemote } from "@/app/utils/chat";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { ChatControllerPool } from "../client/controller"; import { ChatControllerPool } from "../client/controller";
import { DalleSize } from "../typing"; import { DalleSize, DalleQuality, DalleStyle } from "../typing";
import { Prompt, usePromptStore } from "../store/prompt"; import { Prompt, usePromptStore } from "../store/prompt";
import Locale from "../locales"; import Locale from "../locales";
@ -509,9 +511,17 @@ export function ChatActions(props: {
const current_day_token = localStorage.getItem("current_day_token") ?? ""; const current_day_token = localStorage.getItem("current_day_token") ?? "";
const [showSizeSelector, setShowSizeSelector] = useState(false); const [showSizeSelector, setShowSizeSelector] = useState(false);
const [showQualitySelector, setShowQualitySelector] = useState(false);
const [showStyleSelector, setShowStyleSelector] = useState(false);
const dalle3Sizes: DalleSize[] = ["1024x1024", "1792x1024", "1024x1792"]; const dalle3Sizes: DalleSize[] = ["1024x1024", "1792x1024", "1024x1792"];
const dalle3Qualitys: DalleQuality[] = ["standard", "hd"];
const dalle3Styles: DalleStyle[] = ["vivid", "natural"];
const currentSize = const currentSize =
chatStore.currentSession().mask.modelConfig?.size ?? "1024x1024"; chatStore.currentSession().mask.modelConfig?.size ?? "1024x1024";
const currentQuality =
chatStore.currentSession().mask.modelConfig?.quality ?? "standard";
const currentStyle =
chatStore.currentSession().mask.modelConfig?.style ?? "vivid";
useEffect(() => { useEffect(() => {
const show = isVisionModel(currentModel); const show = isVisionModel(currentModel);
@ -686,6 +696,60 @@ export function ChatActions(props: {
/> />
)} )}
{isDalle3(currentModel) && (
<ChatAction
onClick={() => setShowQualitySelector(true)}
text={currentQuality}
icon={<QualityIcon />}
/>
)}
{showQualitySelector && (
<Selector
defaultSelectedValue={currentQuality}
items={dalle3Qualitys.map((m) => ({
title: m,
value: m,
}))}
onClose={() => setShowQualitySelector(false)}
onSelection={(q) => {
if (q.length === 0) return;
const quality = q[0];
chatStore.updateCurrentSession((session) => {
session.mask.modelConfig.quality = quality;
});
showToast(quality);
}}
/>
)}
{isDalle3(currentModel) && (
<ChatAction
onClick={() => setShowStyleSelector(true)}
text={currentStyle}
icon={<StyleIcon />}
/>
)}
{showStyleSelector && (
<Selector
defaultSelectedValue={currentStyle}
items={dalle3Styles.map((m) => ({
title: m,
value: m,
}))}
onClose={() => setShowStyleSelector(false)}
onSelection={(s) => {
if (s.length === 0) return;
const style = s[0];
chatStore.updateCurrentSession((session) => {
session.mask.modelConfig.style = style;
});
showToast(style);
}}
/>
)}
<ChatAction <ChatAction
onClick={() => setShowPluginSelector(true)} onClick={() => setShowPluginSelector(true)}
text={Locale.Plugin.Name} text={Locale.Plugin.Name}
@ -1436,6 +1500,8 @@ function _Chat() {
<IconButton <IconButton
icon={<RenameIcon />} icon={<RenameIcon />}
bordered bordered
title={Locale.Chat.EditMessage.Title}
aria={Locale.Chat.EditMessage.Title}
onClick={() => setIsEditingMessage(true)} onClick={() => setIsEditingMessage(true)}
/> />
</div> </div>
@ -1455,6 +1521,8 @@ function _Chat() {
<IconButton <IconButton
icon={config.tightBorder ? <MinIcon /> : <MaxIcon />} icon={config.tightBorder ? <MinIcon /> : <MaxIcon />}
bordered bordered
title={Locale.Chat.Actions.FullScreen}
aria={Locale.Chat.Actions.FullScreen}
onClick={() => { onClick={() => {
config.update( config.update(
(config) => (config.tightBorder = !config.tightBorder), (config) => (config.tightBorder = !config.tightBorder),
@ -1506,6 +1574,7 @@ function _Chat() {
<div className={styles["chat-message-edit"]}> <div className={styles["chat-message-edit"]}>
<IconButton <IconButton
icon={<EditIcon />} icon={<EditIcon />}
aria={Locale.Chat.Actions.Edit}
onClick={async () => { onClick={async () => {
const newMessage = await showPrompt( const newMessage = await showPrompt(
Locale.Chat.Actions.Edit, Locale.Chat.Actions.Edit,

View File

@ -9,6 +9,7 @@ interface InputRangeProps {
min: string; min: string;
max: string; max: string;
step: string; step: string;
aria: string;
} }
export function InputRange({ export function InputRange({
@ -19,11 +20,13 @@ export function InputRange({
min, min,
max, max,
step, step,
aria,
}: InputRangeProps) { }: InputRangeProps) {
return ( return (
<div className={styles["input-range"] + ` ${className ?? ""}`}> <div className={styles["input-range"] + ` ${className ?? ""}`}>
{title || value} {title || value}
<input <input
aria-label={aria}
type="range" type="range"
title={title} title={title}
value={value} value={value}

View File

@ -127,6 +127,8 @@ export function MaskConfig(props: {
onClose={() => setShowPicker(false)} onClose={() => setShowPicker(false)}
> >
<div <div
tabIndex={0}
aria-label={Locale.Mask.Config.Avatar}
onClick={() => setShowPicker(true)} onClick={() => setShowPicker(true)}
style={{ cursor: "pointer" }} style={{ cursor: "pointer" }}
> >
@ -139,6 +141,7 @@ export function MaskConfig(props: {
</ListItem> </ListItem>
<ListItem title={Locale.Mask.Config.Name}> <ListItem title={Locale.Mask.Config.Name}>
<input <input
aria-label={Locale.Mask.Config.Name}
type="text" type="text"
value={props.mask.name} value={props.mask.name}
onInput={(e) => onInput={(e) =>
@ -153,6 +156,7 @@ export function MaskConfig(props: {
subTitle={Locale.Mask.Config.HideContext.SubTitle} subTitle={Locale.Mask.Config.HideContext.SubTitle}
> >
<input <input
aria-label={Locale.Mask.Config.HideContext.Title}
type="checkbox" type="checkbox"
checked={props.mask.hideContext} checked={props.mask.hideContext}
onChange={(e) => { onChange={(e) => {
@ -169,6 +173,7 @@ export function MaskConfig(props: {
subTitle={Locale.Mask.Config.Share.SubTitle} subTitle={Locale.Mask.Config.Share.SubTitle}
> >
<IconButton <IconButton
aria={Locale.Mask.Config.Share.Title}
icon={<CopyIcon />} icon={<CopyIcon />}
text={Locale.Mask.Config.Share.Action} text={Locale.Mask.Config.Share.Action}
onClick={copyMaskLink} onClick={copyMaskLink}
@ -182,6 +187,7 @@ export function MaskConfig(props: {
subTitle={Locale.Mask.Config.Sync.SubTitle} subTitle={Locale.Mask.Config.Sync.SubTitle}
> >
<input <input
aria-label={Locale.Mask.Config.Sync.Title}
type="checkbox" type="checkbox"
checked={props.mask.syncGlobalConfig} checked={props.mask.syncGlobalConfig}
onChange={async (e) => { onChange={async (e) => {

View File

@ -17,6 +17,7 @@ export function ModelConfigList(props: {
<> <>
<ListItem title={Locale.Settings.Model}> <ListItem title={Locale.Settings.Model}>
<Select <Select
aria-label={Locale.Settings.Model}
value={value} value={value}
onChange={(e) => { onChange={(e) => {
const [model, providerName] = e.currentTarget.value.split("@"); const [model, providerName] = e.currentTarget.value.split("@");
@ -40,6 +41,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.Temperature.SubTitle} subTitle={Locale.Settings.Temperature.SubTitle}
> >
<InputRange <InputRange
aria={Locale.Settings.Temperature.Title}
value={props.modelConfig.temperature?.toFixed(1)} value={props.modelConfig.temperature?.toFixed(1)}
min="0" min="0"
max="1" // lets limit it to 0-1 max="1" // lets limit it to 0-1
@ -59,6 +61,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.TopP.SubTitle} subTitle={Locale.Settings.TopP.SubTitle}
> >
<InputRange <InputRange
aria={Locale.Settings.TopP.Title}
value={(props.modelConfig.top_p ?? 1).toFixed(1)} value={(props.modelConfig.top_p ?? 1).toFixed(1)}
min="0" min="0"
max="1" max="1"
@ -78,6 +81,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.MaxTokens.SubTitle} subTitle={Locale.Settings.MaxTokens.SubTitle}
> >
<input <input
aria-label={Locale.Settings.MaxTokens.Title}
type="number" type="number"
min={1024} min={1024}
max={512000} max={512000}
@ -100,6 +104,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.PresencePenalty.SubTitle} subTitle={Locale.Settings.PresencePenalty.SubTitle}
> >
<InputRange <InputRange
aria={Locale.Settings.PresencePenalty.Title}
value={props.modelConfig.presence_penalty?.toFixed(1)} value={props.modelConfig.presence_penalty?.toFixed(1)}
min="-2" min="-2"
max="2" max="2"
@ -121,6 +126,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.FrequencyPenalty.SubTitle} subTitle={Locale.Settings.FrequencyPenalty.SubTitle}
> >
<InputRange <InputRange
aria={Locale.Settings.FrequencyPenalty.Title}
value={props.modelConfig.frequency_penalty?.toFixed(1)} value={props.modelConfig.frequency_penalty?.toFixed(1)}
min="-2" min="-2"
max="2" max="2"
@ -142,6 +148,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.InjectSystemPrompts.SubTitle} subTitle={Locale.Settings.InjectSystemPrompts.SubTitle}
> >
<input <input
aria-label={Locale.Settings.InjectSystemPrompts.Title}
type="checkbox" type="checkbox"
checked={props.modelConfig.enableInjectSystemPrompts} checked={props.modelConfig.enableInjectSystemPrompts}
onChange={(e) => onChange={(e) =>
@ -159,6 +166,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.InputTemplate.SubTitle} subTitle={Locale.Settings.InputTemplate.SubTitle}
> >
<input <input
aria-label={Locale.Settings.InputTemplate.Title}
type="text" type="text"
value={props.modelConfig.template} value={props.modelConfig.template}
onChange={(e) => onChange={(e) =>
@ -175,6 +183,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.HistoryCount.SubTitle} subTitle={Locale.Settings.HistoryCount.SubTitle}
> >
<InputRange <InputRange
aria={Locale.Settings.HistoryCount.Title}
title={props.modelConfig.historyMessageCount.toString()} title={props.modelConfig.historyMessageCount.toString()}
value={props.modelConfig.historyMessageCount} value={props.modelConfig.historyMessageCount}
min="0" min="0"
@ -193,6 +202,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.CompressThreshold.SubTitle} subTitle={Locale.Settings.CompressThreshold.SubTitle}
> >
<input <input
aria-label={Locale.Settings.CompressThreshold.Title}
type="number" type="number"
min={500} min={500}
max={4000} max={4000}
@ -208,6 +218,7 @@ export function ModelConfigList(props: {
</ListItem> </ListItem>
<ListItem title={Locale.Memory.Title} subTitle={Locale.Memory.Send}> <ListItem title={Locale.Memory.Title} subTitle={Locale.Memory.Send}>
<input <input
aria-label={Locale.Memory.Title}
type="checkbox" type="checkbox"
checked={props.modelConfig.sendMemory} checked={props.modelConfig.sendMemory}
onChange={(e) => onChange={(e) =>

View File

@ -192,6 +192,7 @@ export function ControlParam(props: {
required={item.required} required={item.required}
> >
<Select <Select
aria-label={item.name}
value={props.data[item.value]} value={props.data[item.value]}
onChange={(e) => { onChange={(e) => {
props.onChange(item.value, e.currentTarget.value); props.onChange(item.value, e.currentTarget.value);
@ -216,6 +217,7 @@ export function ControlParam(props: {
required={item.required} required={item.required}
> >
<input <input
aria-label={item.name}
type="number" type="number"
min={item.min} min={item.min}
max={item.max} max={item.max}
@ -235,6 +237,7 @@ export function ControlParam(props: {
required={item.required} required={item.required}
> >
<input <input
aria-label={item.name}
type="text" type="text"
value={props.data[item.value]} value={props.data[item.value]}
style={{ maxWidth: "100%", width: "100%" }} style={{ maxWidth: "100%", width: "100%" }}

View File

@ -135,6 +135,7 @@ export function Sd() {
{showMaxIcon && ( {showMaxIcon && (
<div className="window-action-button"> <div className="window-action-button">
<IconButton <IconButton
aria={Locale.Chat.Actions.FullScreen}
icon={config.tightBorder ? <MinIcon /> : <MaxIcon />} icon={config.tightBorder ? <MinIcon /> : <MaxIcon />}
bordered bordered
onClick={() => { onClick={() => {

View File

@ -246,6 +246,7 @@ function DangerItems() {
subTitle={Locale.Settings.Danger.Reset.SubTitle} subTitle={Locale.Settings.Danger.Reset.SubTitle}
> >
<IconButton <IconButton
aria={Locale.Settings.Danger.Reset.Title}
text={Locale.Settings.Danger.Reset.Action} text={Locale.Settings.Danger.Reset.Action}
onClick={async () => { onClick={async () => {
if (await showConfirm(Locale.Settings.Danger.Reset.Confirm)) { if (await showConfirm(Locale.Settings.Danger.Reset.Confirm)) {
@ -260,6 +261,7 @@ function DangerItems() {
subTitle={Locale.Settings.Danger.Clear.SubTitle} subTitle={Locale.Settings.Danger.Clear.SubTitle}
> >
<IconButton <IconButton
aria={Locale.Settings.Danger.Clear.Title}
text={Locale.Settings.Danger.Clear.Action} text={Locale.Settings.Danger.Clear.Action}
onClick={async () => { onClick={async () => {
if (await showConfirm(Locale.Settings.Danger.Clear.Confirm)) { if (await showConfirm(Locale.Settings.Danger.Clear.Confirm)) {
@ -513,6 +515,7 @@ function SyncItems() {
{/*>*/} {/*>*/}
{/* <div style={{ display: "flex" }}>*/} {/* <div style={{ display: "flex" }}>*/}
{/* <IconButton*/} {/* <IconButton*/}
{/* aria={Locale.Settings.Sync.CloudState + Locale.UI.Config}*/}
{/* icon={<ConfigIcon />}*/} {/* icon={<ConfigIcon />}*/}
{/* text={Locale.UI.Config}*/} {/* text={Locale.UI.Config}*/}
{/* onClick={() => {*/} {/* onClick={() => {*/}
@ -543,6 +546,7 @@ function SyncItems() {
> >
<div style={{ display: "flex" }}> <div style={{ display: "flex" }}>
<IconButton <IconButton
aria={Locale.Settings.Sync.LocalState + Locale.UI.Export}
icon={<UploadIcon />} icon={<UploadIcon />}
text={Locale.UI.Export} text={Locale.UI.Export}
onClick={() => { onClick={() => {
@ -550,6 +554,7 @@ function SyncItems() {
}} }}
/> />
<IconButton <IconButton
aria={Locale.Settings.Sync.LocalState + Locale.UI.Import}
icon={<DownloadIcon />} icon={<DownloadIcon />}
text={Locale.UI.Import} text={Locale.UI.Import}
onClick={() => { onClick={() => {
@ -687,6 +692,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.CustomEndpoint.SubTitle} subTitle={Locale.Settings.Access.CustomEndpoint.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.CustomEndpoint.Title}
type="checkbox" type="checkbox"
checked={accessStore.useCustomConfig} checked={accessStore.useCustomConfig}
onChange={(e) => onChange={(e) =>
@ -706,6 +712,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.OpenAI.Endpoint.SubTitle} subTitle={Locale.Settings.Access.OpenAI.Endpoint.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.OpenAI.Endpoint.Title}
type="text" type="text"
value={accessStore.openaiUrl} value={accessStore.openaiUrl}
placeholder={OPENAI_BASE_URL} placeholder={OPENAI_BASE_URL}
@ -721,6 +728,8 @@ export function Settings() {
subTitle={Locale.Settings.Access.OpenAI.ApiKey.SubTitle} subTitle={Locale.Settings.Access.OpenAI.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria={Locale.Settings.ShowPassword}
aria-label={Locale.Settings.Access.OpenAI.ApiKey.Title}
value={accessStore.openaiApiKey} value={accessStore.openaiApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.OpenAI.ApiKey.Placeholder} placeholder={Locale.Settings.Access.OpenAI.ApiKey.Placeholder}
@ -744,6 +753,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.Azure.Endpoint.Title}
type="text" type="text"
value={accessStore.azureUrl} value={accessStore.azureUrl}
placeholder={Azure.ExampleEndpoint} placeholder={Azure.ExampleEndpoint}
@ -759,6 +769,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Azure.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Azure.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Azure.ApiKey.Title}
value={accessStore.azureApiKey} value={accessStore.azureApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Azure.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Azure.ApiKey.Placeholder}
@ -774,6 +785,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Azure.ApiVerion.SubTitle} subTitle={Locale.Settings.Access.Azure.ApiVerion.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.Azure.ApiVerion.Title}
type="text" type="text"
value={accessStore.azureApiVersion} value={accessStore.azureApiVersion}
placeholder="2023-08-01-preview" placeholder="2023-08-01-preview"
@ -798,6 +810,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.Google.Endpoint.Title}
type="text" type="text"
value={accessStore.googleUrl} value={accessStore.googleUrl}
placeholder={Google.ExampleEndpoint} placeholder={Google.ExampleEndpoint}
@ -813,6 +826,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Google.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Google.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Google.ApiKey.Title}
value={accessStore.googleApiKey} value={accessStore.googleApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Google.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Google.ApiKey.Placeholder}
@ -828,6 +842,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Google.ApiVersion.SubTitle} subTitle={Locale.Settings.Access.Google.ApiVersion.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.Google.ApiVersion.Title}
type="text" type="text"
value={accessStore.googleApiVersion} value={accessStore.googleApiVersion}
placeholder="2023-08-01-preview" placeholder="2023-08-01-preview"
@ -843,6 +858,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Google.GoogleSafetySettings.SubTitle} subTitle={Locale.Settings.Access.Google.GoogleSafetySettings.SubTitle}
> >
<Select <Select
aria-label={Locale.Settings.Access.Google.GoogleSafetySettings.Title}
value={accessStore.googleSafetySettings} value={accessStore.googleSafetySettings}
onChange={(e) => { onChange={(e) => {
accessStore.update( accessStore.update(
@ -873,6 +889,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.Anthropic.Endpoint.Title}
type="text" type="text"
value={accessStore.anthropicUrl} value={accessStore.anthropicUrl}
placeholder={Anthropic.ExampleEndpoint} placeholder={Anthropic.ExampleEndpoint}
@ -888,6 +905,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Anthropic.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Anthropic.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Anthropic.ApiKey.Title}
value={accessStore.anthropicApiKey} value={accessStore.anthropicApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Anthropic.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Anthropic.ApiKey.Placeholder}
@ -903,6 +921,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Anthropic.ApiVerion.SubTitle} subTitle={Locale.Settings.Access.Anthropic.ApiVerion.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.Anthropic.ApiVerion.Title}
type="text" type="text"
value={accessStore.anthropicApiVersion} value={accessStore.anthropicApiVersion}
placeholder={Anthropic.Vision} placeholder={Anthropic.Vision}
@ -924,6 +943,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Baidu.Endpoint.SubTitle} subTitle={Locale.Settings.Access.Baidu.Endpoint.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.Baidu.Endpoint.Title}
type="text" type="text"
value={accessStore.baiduUrl} value={accessStore.baiduUrl}
placeholder={Baidu.ExampleEndpoint} placeholder={Baidu.ExampleEndpoint}
@ -939,6 +959,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Baidu.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Baidu.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Baidu.ApiKey.Title}
value={accessStore.baiduApiKey} value={accessStore.baiduApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Baidu.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Baidu.ApiKey.Placeholder}
@ -954,6 +975,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Baidu.SecretKey.SubTitle} subTitle={Locale.Settings.Access.Baidu.SecretKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Baidu.SecretKey.Title}
value={accessStore.baiduSecretKey} value={accessStore.baiduSecretKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Baidu.SecretKey.Placeholder} placeholder={Locale.Settings.Access.Baidu.SecretKey.Placeholder}
@ -975,6 +997,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Tencent.Endpoint.SubTitle} subTitle={Locale.Settings.Access.Tencent.Endpoint.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.Tencent.Endpoint.Title}
type="text" type="text"
value={accessStore.tencentUrl} value={accessStore.tencentUrl}
placeholder={Tencent.ExampleEndpoint} placeholder={Tencent.ExampleEndpoint}
@ -990,6 +1013,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Tencent.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Tencent.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Tencent.ApiKey.Title}
value={accessStore.tencentSecretId} value={accessStore.tencentSecretId}
type="text" type="text"
placeholder={Locale.Settings.Access.Tencent.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Tencent.ApiKey.Placeholder}
@ -1005,6 +1029,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Tencent.SecretKey.SubTitle} subTitle={Locale.Settings.Access.Tencent.SecretKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Tencent.SecretKey.Title}
value={accessStore.tencentSecretKey} value={accessStore.tencentSecretKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Tencent.SecretKey.Placeholder} placeholder={Locale.Settings.Access.Tencent.SecretKey.Placeholder}
@ -1029,6 +1054,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.ByteDance.Endpoint.Title}
type="text" type="text"
value={accessStore.bytedanceUrl} value={accessStore.bytedanceUrl}
placeholder={ByteDance.ExampleEndpoint} placeholder={ByteDance.ExampleEndpoint}
@ -1044,6 +1070,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.ByteDance.ApiKey.SubTitle} subTitle={Locale.Settings.Access.ByteDance.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.ByteDance.ApiKey.Title}
value={accessStore.bytedanceApiKey} value={accessStore.bytedanceApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.ByteDance.ApiKey.Placeholder} placeholder={Locale.Settings.Access.ByteDance.ApiKey.Placeholder}
@ -1068,6 +1095,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.Alibaba.Endpoint.Title}
type="text" type="text"
value={accessStore.alibabaUrl} value={accessStore.alibabaUrl}
placeholder={Alibaba.ExampleEndpoint} placeholder={Alibaba.ExampleEndpoint}
@ -1083,6 +1111,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Alibaba.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Alibaba.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Alibaba.ApiKey.Title}
value={accessStore.alibabaApiKey} value={accessStore.alibabaApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Alibaba.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Alibaba.ApiKey.Placeholder}
@ -1107,6 +1136,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.Moonshot.Endpoint.Title}
type="text" type="text"
value={accessStore.moonshotUrl} value={accessStore.moonshotUrl}
placeholder={Moonshot.ExampleEndpoint} placeholder={Moonshot.ExampleEndpoint}
@ -1122,6 +1152,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Moonshot.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Moonshot.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Moonshot.ApiKey.Title}
value={accessStore.moonshotApiKey} value={accessStore.moonshotApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Moonshot.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Moonshot.ApiKey.Placeholder}
@ -1146,6 +1177,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.Stability.Endpoint.Title}
type="text" type="text"
value={accessStore.stabilityUrl} value={accessStore.stabilityUrl}
placeholder={Stability.ExampleEndpoint} placeholder={Stability.ExampleEndpoint}
@ -1161,6 +1193,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Stability.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Stability.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Stability.ApiKey.Title}
value={accessStore.stabilityApiKey} value={accessStore.stabilityApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Stability.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Stability.ApiKey.Placeholder}
@ -1184,6 +1217,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.Iflytek.Endpoint.Title}
type="text" type="text"
value={accessStore.iflytekUrl} value={accessStore.iflytekUrl}
placeholder={Iflytek.ExampleEndpoint} placeholder={Iflytek.ExampleEndpoint}
@ -1199,6 +1233,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Iflytek.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Iflytek.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Iflytek.ApiKey.Title}
value={accessStore.iflytekApiKey} value={accessStore.iflytekApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Iflytek.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Iflytek.ApiKey.Placeholder}
@ -1215,6 +1250,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Iflytek.ApiSecret.SubTitle} subTitle={Locale.Settings.Access.Iflytek.ApiSecret.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Iflytek.ApiSecret.Title}
value={accessStore.iflytekApiSecret} value={accessStore.iflytekApiSecret}
type="text" type="text"
placeholder={Locale.Settings.Access.Iflytek.ApiSecret.Placeholder} placeholder={Locale.Settings.Access.Iflytek.ApiSecret.Placeholder}
@ -1244,6 +1280,7 @@ export function Settings() {
<div className="window-action-button"></div> <div className="window-action-button"></div>
<div className="window-action-button"> <div className="window-action-button">
<IconButton <IconButton
aria={Locale.UI.Close}
icon={<CloseIcon />} icon={<CloseIcon />}
onClick={() => navigate(Path.Home)} onClick={() => navigate(Path.Home)}
bordered bordered
@ -1267,6 +1304,8 @@ export function Settings() {
open={showEmojiPicker} open={showEmojiPicker}
> >
<div <div
aria-label={Locale.Settings.Avatar}
tabIndex={0}
className={styles.avatar} className={styles.avatar}
onClick={() => { onClick={() => {
setShowEmojiPicker(!showEmojiPicker); setShowEmojiPicker(!showEmojiPicker);
@ -1304,6 +1343,7 @@ export function Settings() {
{/*<ListItem title={Locale.Settings.SendKey}>*/} {/*<ListItem title={Locale.Settings.SendKey}>*/}
{/* <Select*/} {/* <Select*/}
{/* aria-label={Locale.Settings.SendKey}*/}
{/* value={config.submitKey}*/} {/* value={config.submitKey}*/}
{/* onChange={(e) => {*/} {/* onChange={(e) => {*/}
{/* updateConfig(*/} {/* updateConfig(*/}
@ -1322,6 +1362,7 @@ export function Settings() {
<ListItem title={Locale.Settings.Theme}> <ListItem title={Locale.Settings.Theme}>
<Select <Select
aria-label={Locale.Settings.Theme}
value={config.theme} value={config.theme}
onChange={(e) => { onChange={(e) => {
updateConfig( updateConfig(
@ -1339,6 +1380,7 @@ export function Settings() {
{/*<ListItem title={Locale.Settings.Lang.Name}>*/} {/*<ListItem title={Locale.Settings.Lang.Name}>*/}
{/* <Select*/} {/* <Select*/}
{/* aria-label={Locale.Settings.Lang.Name}*/}
{/* value={getLang()}*/} {/* value={getLang()}*/}
{/* onChange={(e) => {*/} {/* onChange={(e) => {*/}
{/* changeLang(e.target.value as any);*/} {/* changeLang(e.target.value as any);*/}
@ -1357,6 +1399,7 @@ export function Settings() {
subTitle={Locale.Settings.FontSize.SubTitle} subTitle={Locale.Settings.FontSize.SubTitle}
> >
<InputRange <InputRange
aria={Locale.Settings.FontSize.Title}
title={`${config.fontSize ?? 14}px`} title={`${config.fontSize ?? 14}px`}
value={config.fontSize} value={config.fontSize}
min="12" min="12"
@ -1376,6 +1419,7 @@ export function Settings() {
subTitle={Locale.Settings.FontFamily.SubTitle} subTitle={Locale.Settings.FontFamily.SubTitle}
> >
<input <input
aria-label={Locale.Settings.FontFamily.Title}
type="text" type="text"
value={config.fontFamily} value={config.fontFamily}
placeholder={Locale.Settings.FontFamily.Placeholder} placeholder={Locale.Settings.FontFamily.Placeholder}
@ -1392,6 +1436,7 @@ export function Settings() {
{/* subTitle={Locale.Settings.AutoGenerateTitle.SubTitle}*/} {/* subTitle={Locale.Settings.AutoGenerateTitle.SubTitle}*/}
{/*>*/} {/*>*/}
{/* <input*/} {/* <input*/}
{/* aria-label={Locale.Settings.AutoGenerateTitle.Title}*/}
{/* type="checkbox"*/} {/* type="checkbox"*/}
{/* checked={config.enableAutoGenerateTitle}*/} {/* checked={config.enableAutoGenerateTitle}*/}
{/* onChange={(e) =>*/} {/* onChange={(e) =>*/}
@ -1408,6 +1453,7 @@ export function Settings() {
{/* subTitle={Locale.Settings.SendPreviewBubble.SubTitle}*/} {/* subTitle={Locale.Settings.SendPreviewBubble.SubTitle}*/}
{/*>*/} {/*>*/}
{/* <input*/} {/* <input*/}
{/* aria-label={Locale.Settings.SendPreviewBubble.Title}*/}
{/* type="checkbox"*/} {/* type="checkbox"*/}
{/* checked={config.sendPreviewBubble}*/} {/* checked={config.sendPreviewBubble}*/}
{/* onChange={(e) =>*/} {/* onChange={(e) =>*/}
@ -1428,6 +1474,7 @@ export function Settings() {
{/* subTitle={Locale.Settings.Mask.Splash.SubTitle}*/} {/* subTitle={Locale.Settings.Mask.Splash.SubTitle}*/}
{/* >*/} {/* >*/}
{/* <input*/} {/* <input*/}
{/* aria-label={Locale.Settings.Mask.Splash.Title}*/}
{/* type="checkbox"*/} {/* type="checkbox"*/}
{/* checked={!config.dontShowMaskSplashScreen}*/} {/* checked={!config.dontShowMaskSplashScreen}*/}
{/* onChange={(e) =>*/} {/* onChange={(e) =>*/}
@ -1445,6 +1492,7 @@ export function Settings() {
{/* subTitle={Locale.Settings.Mask.Builtin.SubTitle}*/} {/* subTitle={Locale.Settings.Mask.Builtin.SubTitle}*/}
{/* >*/} {/* >*/}
{/* <input*/} {/* <input*/}
{/* aria-label={Locale.Settings.Mask.Builtin.Title}*/}
{/* type="checkbox"*/} {/* type="checkbox"*/}
{/* checked={config.hideBuiltinMasks}*/} {/* checked={config.hideBuiltinMasks}*/}
{/* onChange={(e) =>*/} {/* onChange={(e) =>*/}
@ -1463,6 +1511,7 @@ export function Settings() {
subTitle={Locale.Settings.Prompt.Disable.SubTitle} subTitle={Locale.Settings.Prompt.Disable.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Prompt.Disable.Title}
type="checkbox" type="checkbox"
checked={config.disablePromptHint} checked={config.disablePromptHint}
onChange={(e) => onChange={(e) =>
@ -1482,6 +1531,7 @@ export function Settings() {
)} )}
> >
<IconButton <IconButton
aria={Locale.Settings.Prompt.List + Locale.Settings.Prompt.Edit}
icon={<EditIcon />} icon={<EditIcon />}
text={Locale.Settings.Prompt.Edit} text={Locale.Settings.Prompt.Edit}
onClick={() => setShowPromptModal(true)} onClick={() => setShowPromptModal(true)}
@ -1496,29 +1546,30 @@ export function Settings() {
{/* <>*/} {/* <>*/}
{/* {useCustomConfigComponent}*/} {/* {useCustomConfigComponent}*/}
{/* {accessStore.useCustomConfig && (*/} {/*{accessStore.useCustomConfig && (*/}
{/* <>*/} {/* <>*/}
{/* <ListItem*/} {/* <ListItem*/}
{/* title={Locale.Settings.Access.Provider.Title}*/} {/* title={Locale.Settings.Access.Provider.Title}*/}
{/* subTitle={Locale.Settings.Access.Provider.SubTitle}*/} {/* subTitle={Locale.Settings.Access.Provider.SubTitle}*/}
{/* >*/} {/* >*/}
{/* <Select*/} {/* <Select*/}
{/* value={accessStore.provider}*/} {/* aria-label={Locale.Settings.Access.Provider.Title}*/}
{/* onChange={(e) => {*/} {/* value={accessStore.provider}*/}
{/* accessStore.update(*/} {/* onChange={(e) => {*/}
{/* (access) =>*/} {/* accessStore.update(*/}
{/* (access.provider = e.target*/} {/* (access) =>*/}
{/* .value as ServiceProvider),*/} {/* (access.provider = e.target*/}
{/* );*/} {/* .value as ServiceProvider),*/}
{/* }}*/} {/* );*/}
{/* >*/} {/* }}*/}
{/* {Object.entries(ServiceProvider).map(([k, v]) => (*/} {/* >*/}
{/* <option value={v} key={k}>*/} {/* {Object.entries(ServiceProvider).map(([k, v]) => (*/}
{/* {k}*/} {/* <option value={v} key={k}>*/}
{/* </option>*/} {/* {k}*/}
{/* ))}*/} {/* </option>*/}
{/* </Select>*/} {/* ))}*/}
{/* </ListItem>*/} {/* </Select>*/}
{/* </ListItem>*/}
{/* {openAIConfigComponent}*/} {/* {openAIConfigComponent}*/}
{/* {azureConfigComponent}*/} {/* {azureConfigComponent}*/}
@ -1567,6 +1618,7 @@ export function Settings() {
{/* subTitle={Locale.Settings.Access.CustomModel.SubTitle}*/} {/* subTitle={Locale.Settings.Access.CustomModel.SubTitle}*/}
{/* >*/} {/* >*/}
{/* <input*/} {/* <input*/}
{/* aria-label={Locale.Settings.Access.CustomModel.Title}*/}
{/* type="text"*/} {/* type="text"*/}
{/* value={config.customModels}*/} {/* value={config.customModels}*/}
{/* placeholder="model1,model2,model3"*/} {/* placeholder="model1,model2,model3"*/}

View File

@ -348,13 +348,22 @@ export function SideBar(props: { className?: string }) {
</div> </div>
<div className={styles["sidebar-action"]}> <div className={styles["sidebar-action"]}>
<Link to={Path.Settings}> <Link to={Path.Settings}>
<IconButton icon={<SettingsIcon />} shadow /> <IconButton
aria={Locale.Settings.Title}
icon={<SettingsIcon />}
shadow
/>
</Link> </Link>
</div> </div>
<div className={styles["sidebar-action"]}> <div className={styles["sidebar-action"]}>
{/*<a href={REPO_URL} target="_blank" rel="noopener noreferrer">*/} {/*<a href={REPO_URL} target="_blank" rel="noopener noreferrer">*/}
{/* <IconButton icon={<GithubIcon />} shadow />*/} {/* <IconButton*/}
{/* aria={Locale.Export.MessageFromChatGPT}*/}
{/* icon={<GithubIcon />}*/}
{/* shadow*/}
{/* />*/}
{/*</a>*/} {/*</a>*/}
<IconButton <IconButton
onClick={async () => { onClick={async () => {
if (await showConfirm(Locale.Settings.Danger.Clear.Confirm)) { if (await showConfirm(Locale.Settings.Danger.Clear.Confirm)) {

View File

@ -282,9 +282,10 @@ export function Input(props: InputProps) {
); );
} }
export function PasswordInput(props: HTMLProps<HTMLInputElement>) { export function PasswordInput(
props: HTMLProps<HTMLInputElement> & { aria?: string },
) {
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
function changeVisibility() { function changeVisibility() {
setVisible(!visible); setVisible(!visible);
} }
@ -292,6 +293,7 @@ export function PasswordInput(props: HTMLProps<HTMLInputElement>) {
return ( return (
<div className={"password-input-container"}> <div className={"password-input-container"}>
<IconButton <IconButton
aria={props.aria}
icon={visible ? <EyeIcon /> : <EyeOffIcon />} icon={visible ? <EyeIcon /> : <EyeOffIcon />}
onClick={changeVisibility} onClick={changeVisibility}
className={"password-eye"} className={"password-eye"}

View File

@ -245,6 +245,7 @@ export const KnowledgeCutOffDate: Record<string, string> = {
"gpt-4-turbo-2024-04-09": "2023-12", "gpt-4-turbo-2024-04-09": "2023-12",
"gpt-4-turbo-preview": "2023-12", "gpt-4-turbo-preview": "2023-12",
"gpt-4o-2024-05-13": "2023-10", "gpt-4o-2024-05-13": "2023-10",
"gpt-4o-2024-08-06": "2023-10",
"gpt-4o-mini": "2023-10", "gpt-4o-mini": "2023-10",
"gpt-4o-mini-2024-07-18": "2023-10", "gpt-4o-mini-2024-07-18": "2023-10",
"gpt-4-vision-preview": "2023-04", "gpt-4-vision-preview": "2023-04",
@ -266,6 +267,7 @@ const openaiModels = [
"gpt-4-turbo-preview", "gpt-4-turbo-preview",
"gpt-4o", "gpt-4o",
"gpt-4o-2024-05-13", "gpt-4o-2024-05-13",
"gpt-4o-2024-08-06",
"gpt-4o-mini", "gpt-4o-mini",
"gpt-4o-mini-2024-07-18", "gpt-4o-mini-2024-07-18",
"gpt-4-vision-preview", "gpt-4-vision-preview",

4
app/icons/hd.svg Normal file
View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#333" class="bi bi-badge-hd" viewBox="0 0 16 16">
<path d="M7.396 11V5.001H6.209v2.44H3.687V5H2.5v6h1.187V8.43h2.522V11zM8.5 5.001V11h2.188c1.811 0 2.685-1.107 2.685-3.015 0-1.894-.86-2.984-2.684-2.984zm1.187.967h.843c1.112 0 1.622.686 1.622 2.04 0 1.353-.505 2.02-1.622 2.02h-.843z"/>
<path d="M14 3a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zM2 2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2z"/>
</svg>

After

Width:  |  Height:  |  Size: 514 B

4
app/icons/palette.svg Normal file
View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#333" class="bi bi-palette" viewBox="0 0 16 16">
<path d="M8 5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3m4 3a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3M5.5 7a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m.5 6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3"/>
<path d="M16 8c0 3.15-1.866 2.585-3.567 2.07C11.42 9.763 10.465 9.473 10 10c-.603.683-.475 1.819-.351 2.92C9.826 14.495 9.996 16 8 16a8 8 0 1 1 8-8m-8 7c.611 0 .654-.171.655-.176.078-.146.124-.464.07-1.119-.014-.168-.037-.37-.061-.591-.052-.464-.112-1.005-.118-1.462-.01-.707.083-1.61.704-2.314.369-.417.845-.578 1.272-.618.404-.038.812.026 1.16.104.343.077.702.186 1.025.284l.028.008c.346.105.658.199.953.266.653.148.904.083.991.024C14.717 9.38 15 9.161 15 8a7 7 0 1 0-7 7"/>
</svg>

After

Width:  |  Height:  |  Size: 781 B

View File

@ -82,6 +82,7 @@ const cn = {
PinToastAction: "查看", PinToastAction: "查看",
Delete: "删除", Delete: "删除",
Edit: "编辑", Edit: "编辑",
FullScreen: "全屏",
}, },
Commands: { Commands: {
new: "新建聊天", new: "新建聊天",
@ -172,6 +173,7 @@ const cn = {
Settings: { Settings: {
Title: "设置", Title: "设置",
SubTitle: "所有设置选项", SubTitle: "所有设置选项",
ShowPassword: "显示密码",
Danger: { Danger: {
Reset: { Reset: {

View File

@ -84,6 +84,7 @@ const en: LocaleType = {
PinToastAction: "View", PinToastAction: "View",
Delete: "Delete", Delete: "Delete",
Edit: "Edit", Edit: "Edit",
FullScreen: "FullScreen",
}, },
Commands: { Commands: {
new: "Start a new chat", new: "Start a new chat",
@ -175,6 +176,7 @@ const en: LocaleType = {
Settings: { Settings: {
Title: "Settings", Title: "Settings",
SubTitle: "All Settings", SubTitle: "All Settings",
ShowPassword: "ShowPassword",
Danger: { Danger: {
Reset: { Reset: {
Title: "Reset All Settings", Title: "Reset All Settings",

View File

@ -1,5 +1,5 @@
import { LLMModel } from "../client/api"; import { LLMModel } from "../client/api";
import { DalleSize } from "../typing"; import { DalleSize, DalleQuality, DalleStyle } from "../typing";
import { getClientConfig } from "../config/client"; import { getClientConfig } from "../config/client";
import { import {
DEFAULT_INPUT_TEMPLATE, DEFAULT_INPUT_TEMPLATE,
@ -68,6 +68,8 @@ export const DEFAULT_CONFIG = {
enableInjectSystemPrompts: true, enableInjectSystemPrompts: true,
template: config?.template ?? DEFAULT_INPUT_TEMPLATE, template: config?.template ?? DEFAULT_INPUT_TEMPLATE,
size: "1024x1024" as DalleSize, size: "1024x1024" as DalleSize,
quality: "standard" as DalleQuality,
style: "vivid" as DalleStyle,
}, },
}; };

View File

@ -9,3 +9,5 @@ export interface RequestMessage {
} }
export type DalleSize = "1024x1024" | "1792x1024" | "1024x1792"; export type DalleSize = "1024x1024" | "1792x1024" | "1024x1792";
export type DalleQuality = "standard" | "hd";
export type DalleStyle = "vivid" | "natural";