Compare commits

..

12 Commits

Author SHA1 Message Date
lyf
6f75ef8f0a addcd 2024-08-10 12:45:50 +08:00
lyf
8f759d1c3e 代码折叠 2024-08-09 14:55:25 +08:00
lyf
44787637f2 tj 2024-08-08 21:07:03 +08:00
Dogtiti
036358de7c Merge pull request #5219 from ConnectAI-E/feature/access
修复ChatGPTNextWeb页面的无障碍问题
2024-08-08 13:59:16 +08:00
lyf
0958b9ee12 tsxiugai 2024-08-08 13:08:56 +08:00
Dogtiti
aff1d7ecd6 Merge pull request #5223 from 122cygf/main
修复拼写错误
2024-08-07 21:29:43 +08:00
lzz
42fdbd9bb8 Fix spelling errors 2024-08-07 17:22:32 +08:00
lyf
034c82e514 修改设置的无障碍 2024-08-07 13:39:23 +08:00
lyf
14ff46b5cd 解决按钮无障碍 2024-08-07 13:01:08 +08:00
lyf
c9099ca0a5 无障碍按钮和链接 2024-08-07 10:55:02 +08:00
Dogtiti
58b144b345 Merge pull request #5218 from ConnectAI-E/feature/bangpt
解决禁止gpt4时禁止gtp4o-mini问题
2024-08-07 10:45:38 +08:00
lyf
af21c57e77 ban gpt4 2024-08-07 10:15:39 +08:00
16 changed files with 235 additions and 21 deletions

View File

@@ -13,7 +13,7 @@ function getModels(remoteModelRes: OpenAIListModelResponse) {
if (config.disableGPT4) { if (config.disableGPT4) {
remoteModelRes.data = remoteModelRes.data.filter( remoteModelRes.data = remoteModelRes.data.filter(
(m) => !m.id.startsWith("gpt-4"), (m) => !m.id.startsWith("gpt-4") || m.id.startsWith("gpt-4o-mini"),
); );
} }

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

@@ -1337,6 +1337,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>
@@ -1356,6 +1358,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),
@@ -1407,6 +1411,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

@@ -122,20 +122,50 @@ export function PreCode(props: { children: any }) {
} }
}, []); }, []);
// const [collapsed, setCollapsed] = useState(true);
// const [showToggle, setShowToggle] = useState(false);
// useEffect(() => {
// if (ref.current) {
// const codeHeight = ref.current.scrollHeight;
// setShowToggle(codeHeight > 400);
// ref.current.scrollTop = ref.current.scrollHeight;
// }
// }, [props.children]);
// const toggleCollapsed = () => {
// setCollapsed(collapsed=>!collapsed);
// };
return ( return (
<> <>
<pre ref={ref}> <div style={{ position: "relative" }}>
<span <pre
className="copy-code-button" ref={ref}
onClick={() => { style={{
if (ref.current) { // maxHeight: collapsed ? "400px" : "none",
const code = ref.current.innerText; overflowY: "hidden",
copyToClipboard(code);
}
}} }}
></span> >
{props.children} <span
</pre> className="copy-code-button"
onClick={() => {
if (ref.current) {
const code = ref.current.innerText;
copyToClipboard(code);
}
}}
></span>
{props.children}
{/* {showToggle && collapsed && (
<div
className={`show-hide-button ${collapsed ? 'collapsed' : 'expanded'}`}
>
<button onClick={toggleCollapsed}>查看全部</button>
</div>
)} */}
</pre>
</div>
{mermaidCode.length > 0 && ( {mermaidCode.length > 0 && (
<Mermaid code={mermaidCode} key={mermaidCode} /> <Mermaid code={mermaidCode} key={mermaidCode} />
)} )}
@@ -156,6 +186,46 @@ export function PreCode(props: { children: any }) {
); );
} }
function CustomCode(props: { children: any }) {
const ref = useRef<HTMLPreElement>(null);
const [collapsed, setCollapsed] = useState(true);
const [showToggle, setShowToggle] = useState(false);
useEffect(() => {
if (ref.current) {
const codeHeight = ref.current.scrollHeight;
setShowToggle(codeHeight > 400);
ref.current.scrollTop = ref.current.scrollHeight;
}
}, [props.children]);
const toggleCollapsed = () => {
setCollapsed((collapsed) => !collapsed);
};
return (
<>
<code
ref={ref}
style={{
maxHeight: collapsed ? "400px" : "none",
overflowY: "hidden",
}}
>
{props.children}
{showToggle && collapsed && (
<div
className={`show-hide-button ${
collapsed ? "collapsed" : "expanded"
}`}
>
<button onClick={toggleCollapsed}></button>
</div>
)}
</code>
</>
);
}
function escapeDollarNumber(text: string) { function escapeDollarNumber(text: string) {
let escapedText = ""; let escapedText = "";
@@ -196,6 +266,8 @@ function _MarkDownContent(props: { content: string }) {
return escapeBrackets(escapeDollarNumber(props.content)); return escapeBrackets(escapeDollarNumber(props.content));
}, [props.content]); }, [props.content]);
console.log(escapedContent, 11233);
return ( return (
<ReactMarkdown <ReactMarkdown
remarkPlugins={[RemarkMath, RemarkGfm, RemarkBreaks]} remarkPlugins={[RemarkMath, RemarkGfm, RemarkBreaks]}
@@ -211,6 +283,7 @@ function _MarkDownContent(props: { content: string }) {
]} ]}
components={{ components={{
pre: PreCode, pre: PreCode,
code: CustomCode,
p: (pProps) => <p {...pProps} dir="auto" />, p: (pProps) => <p {...pProps} dir="auto" />,
a: (aProps) => { a: (aProps) => {
const href = aProps.href || ""; const href = aProps.href || "";

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

@@ -133,6 +133,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)}
@@ -1503,6 +1553,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Provider.SubTitle} subTitle={Locale.Settings.Access.Provider.SubTitle}
> >
<Select <Select
aria-label={Locale.Settings.Access.Provider.Title}
value={accessStore.provider} value={accessStore.provider}
onChange={(e) => { onChange={(e) => {
accessStore.update( accessStore.update(
@@ -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

@@ -297,12 +297,20 @@ 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>
</div> </div>
</> </>

View File

@@ -265,9 +265,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);
} }
@@ -275,6 +276,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

@@ -119,10 +119,16 @@ export const getServerSideConfig = () => {
if (disableGPT4) { if (disableGPT4) {
if (customModels) customModels += ","; if (customModels) customModels += ",";
customModels += DEFAULT_MODELS.filter((m) => m.name.startsWith("gpt-4")) customModels += DEFAULT_MODELS.filter(
(m) => m.name.startsWith("gpt-4") && !m.name.startsWith("gpt-4o-mini"),
)
.map((m) => "-" + m.name) .map((m) => "-" + m.name)
.join(","); .join(",");
if (defaultModel.startsWith("gpt-4")) defaultModel = ""; if (
defaultModel.startsWith("gpt-4") &&
!defaultModel.startsWith("gpt-4o-mini")
)
defaultModel = "";
} }
const isStability = !!process.env.STABILITY_API_KEY; const isStability = !!process.env.STABILITY_API_KEY;

View File

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

View File

@@ -44,6 +44,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",
@@ -135,6 +136,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

@@ -271,8 +271,7 @@ div.math {
} }
pre { pre {
position: relative; // position: relative;
&:hover .copy-code-button { &:hover .copy-code-button {
pointer-events: all; pointer-events: all;
transform: translateX(0px); transform: translateX(0px);
@@ -304,6 +303,39 @@ pre {
} }
} }
code{
.show-hide-button {
border-radius: 10px;
position: absolute;
top: 0;
left: 0;
right: 0;
width: 100%;
margin: auto;
height: fit-content;
display: inline-flex;
justify-content: center;
button{
margin-top: 3em;
margin-bottom: 4em;
padding: 5px 16px;
border: 0;
cursor: pointer;
border-radius: 14px;
text-align: center;
color: white;
background: #464e4e;
}
}
.expanded {
background-image: none;
}
.collapsed {
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.06));
}
}
.clickable { .clickable {
cursor: pointer; cursor: pointer;