Merge branch 'main' of github.com:7li7li/ChatGPT-Next-Web

# Conflicts:
#	app/components/sidebar.tsx
This commit is contained in:
zhangchenguang01
2024-08-05 10:02:51 +08:00
33 changed files with 317 additions and 38 deletions

View File

@@ -43,7 +43,7 @@ async function handle(
export const GET = handle;
export const POST = handle;
export const runtime = "nodejs";
export const runtime = "edge";
export const preferredRegion = [
"arn1",
"bom1",

View File

@@ -41,13 +41,16 @@ interface ChatCommands {
del?: Command;
}
export const ChatCommandPrefix = ":";
// Compatible with Chinese colon character ""
export const ChatCommandPrefix = /^[:]/;
export function useChatCommand(commands: ChatCommands = {}) {
function extract(userInput: string) {
return (
userInput.startsWith(ChatCommandPrefix) ? userInput.slice(1) : userInput
) as keyof ChatCommands;
const match = userInput.match(ChatCommandPrefix);
if (match) {
return userInput.slice(1) as keyof ChatCommands;
}
return userInput as keyof ChatCommands;
}
function search(userInput: string) {
@@ -57,7 +60,7 @@ export function useChatCommand(commands: ChatCommands = {}) {
.filter((c) => c.startsWith(input))
.map((c) => ({
title: desc[c as keyof ChatCommands],
content: ChatCommandPrefix + c,
content: ":" + c,
}));
}

View File

@@ -732,6 +732,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 +812,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 +1483,7 @@ function _Chat() {
setUserInput(getMessageTextContent(message));
}}
fontSize={fontSize}
fontFamily={fontFamily}
parentRef={scrollRef}
defaultShow={i >= messages.length - 6}
/>
@@ -1576,6 +1578,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

@@ -171,11 +171,11 @@ export function SideBarHeader(props: {
return (
<Fragment>
<div className={styles["sidebar-header"]} data-tauri-drag-region>
<div className={styles["sidebar-title"]} data-tauri-drag-region>
7li-AI
</div>
<div className={styles["sidebar-sub-title"]}>
7li7li提供支持7liai访<a href="https://www.7li7li.cn/support/" target="_blank" rel="noopener noreferrer"></a>
<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-logo"] + " no-dark"}>{logo}</div>
</div>
@@ -225,7 +225,7 @@ export function SideBar(props: { className?: string }) {
{...props}
>
<SideBarHeader
title="7li-AI"
title="NextChat"
subTitle="Build your own AI assistant."
logo={<ChatGptIcon />}
>
@@ -301,7 +301,7 @@ export function SideBar(props: { className?: string }) {
</Link>
</div>
<div className={styles["sidebar-action"]}>
<a href="https://www.7li7li.cn" target="_blank" rel="noopener noreferrer">
<a href={REPO_URL} target="_blank" rel="noopener noreferrer">
<IconButton icon={<GithubIcon />} shadow />
</a>
</div>

View File

@@ -111,6 +111,11 @@ const ar: PartialLocaleType = {
Title: "حجم الخط",
SubTitle: "ضبط حجم الخط لمحتوى الدردشة",
},
FontFamily: {
Title: "خط الدردشة",
SubTitle: "خط محتوى الدردشة، اتركه فارغًا لتطبيق الخط الافتراضي العالمي",
Placeholder: "اسم الخط",
},
InjectSystemPrompts: {
Title: "حقن تلميحات النظام",
SubTitle:

View File

@@ -136,6 +136,12 @@ const bn: PartialLocaleType = {
Title: "ফন্ট সাইজ",
SubTitle: "চ্যাট সামগ্রীর ফন্ট সাইজ সংশোধন করুন",
},
FontFamily: {
Title: "চ্যাট ফন্ট",
SubTitle:
"চ্যাট সামগ্রীর ফন্ট, বিশ্বব্যাপী ডিফল্ট ফন্ট প্রয়োগ করতে খালি রাখুন",
Placeholder: "ফন্টের নাম",
},
InjectSystemPrompts: {
Title: "حقن تلميحات النظام",
SubTitle:

View File

@@ -156,6 +156,11 @@ const cn = {
Title: "字体大小",
SubTitle: "聊天内容的字体大小",
},
FontFamily: {
Title: "聊天字体",
SubTitle: "聊天内容的字体,若置空则应用全局默认字体",
Placeholder: "字体名称",
},
InjectSystemPrompts: {
Title: "注入系统级提示信息",
SubTitle: "强制给每次请求的消息列表开头添加一个模拟 ChatGPT 的系统提示",

View File

@@ -71,6 +71,12 @@ const cs: PartialLocaleType = {
Title: "Velikost písma",
SubTitle: "Nastavení velikosti písma obsahu chatu",
},
FontFamily: {
Title: "Chatové Písmo",
SubTitle:
"Písmo obsahu chatu, ponechejte prázdné pro použití globálního výchozího písma",
Placeholder: "Název Písma",
},
InjectSystemPrompts: {
Title: "Vložit systémové prompty",
SubTitle:

View File

@@ -71,6 +71,12 @@ const de: PartialLocaleType = {
Title: "Schriftgröße",
SubTitle: "Schriftgröße des Chat-Inhalts anpassen",
},
FontFamily: {
Title: "Chat-Schriftart",
SubTitle:
"Schriftart des Chat-Inhalts, leer lassen, um die globale Standardschriftart anzuwenden",
Placeholder: "Schriftartname",
},
InjectSystemPrompts: {
Title: "System-Prompts einfügen",
SubTitle:

View File

@@ -158,6 +158,12 @@ const en: LocaleType = {
Title: "Font Size",
SubTitle: "Adjust font size of chat content",
},
FontFamily: {
Title: "Chat Font Family",
SubTitle:
"Font Family of the chat content, leave empty to apply global default font",
Placeholder: "Font Family Name",
},
InjectSystemPrompts: {
Title: "Inject System Prompts",
SubTitle: "Inject a global system prompt for every request",

View File

@@ -71,6 +71,12 @@ const es: PartialLocaleType = {
Title: "Tamaño de fuente",
SubTitle: "Ajustar el tamaño de fuente del contenido del chat",
},
FontFamily: {
Title: "Fuente del Chat",
SubTitle:
"Fuente del contenido del chat, dejar vacío para aplicar la fuente predeterminada global",
Placeholder: "Nombre de la Fuente",
},
InjectSystemPrompts: {
Title: "Inyectar Prompts del Sistema",
SubTitle:

View File

@@ -111,6 +111,12 @@ const fr: PartialLocaleType = {
Title: "Taille des polices",
SubTitle: "Ajuste la taille de police du contenu de la conversation",
},
FontFamily: {
Title: "Police de Chat",
SubTitle:
"Police du contenu du chat, laissez vide pour appliquer la police par défaut globale",
Placeholder: "Nom de la Police",
},
InjectSystemPrompts: {
Title: "Injecter des invites système",
SubTitle:

View File

@@ -140,6 +140,12 @@ const id: PartialLocaleType = {
Title: "Ukuran Font",
SubTitle: "Ubah ukuran font konten chat",
},
FontFamily: {
Title: "Font Obrolan",
SubTitle:
"Font dari konten obrolan, biarkan kosong untuk menerapkan font default global",
Placeholder: "Nama Font",
},
InjectSystemPrompts: {
Title: "Suntikkan Petunjuk Sistem",
SubTitle:
@@ -369,8 +375,8 @@ const id: PartialLocaleType = {
},
Exporter: {
Description: {
Title: "Hanya pesan setelah menghapus konteks yang akan ditampilkan"
},
Title: "Hanya pesan setelah menghapus konteks yang akan ditampilkan",
},
Model: "Model",
Messages: "Pesan",
Topic: "Topik",

View File

@@ -71,6 +71,12 @@ const it: PartialLocaleType = {
Title: "Dimensione carattere",
SubTitle: "Regolare la dimensione dei caratteri del contenuto della chat",
},
FontFamily: {
Title: "Font della Chat",
SubTitle:
"Carattere del contenuto della chat, lascia vuoto per applicare il carattere predefinito globale",
Placeholder: "Nome del Font",
},
InjectSystemPrompts: {
Title: "Inserisci Prompts di Sistema",
SubTitle:

View File

@@ -118,6 +118,12 @@ const jp: PartialLocaleType = {
Title: "フォントサイズ",
SubTitle: "チャット内容のフォントサイズ",
},
FontFamily: {
Title: "チャットフォント",
SubTitle:
"チャットコンテンツのフォント、空白の場合はグローバルデフォルトフォントを適用します",
Placeholder: "フォント名",
},
InjectSystemPrompts: {
Title: "システムプロンプトの挿入",
SubTitle:

View File

@@ -72,6 +72,11 @@ const ko: PartialLocaleType = {
Title: "글꼴 크기",
SubTitle: "채팅 내용의 글꼴 크기 조정",
},
FontFamily: {
Title: "채팅 폰트",
SubTitle: "채팅 내용의 폰트, 비워 두면 글로벌 기본 폰트를 적용",
Placeholder: "폰트 이름",
},
InjectSystemPrompts: {
Title: "시스템 프롬프트 주입",
SubTitle:

View File

@@ -66,6 +66,12 @@ const no: PartialLocaleType = {
Title: "Fontstørrelsen",
SubTitle: "Juster fontstørrelsen for samtaleinnholdet.",
},
FontFamily: {
Title: "Chat-skrifttype",
SubTitle:
"Skrifttypen for chatinnhold, la stå tom for å bruke global standardskrifttype",
Placeholder: "Skriftnavn",
},
InjectSystemPrompts: {
Title: "Sett inn systemprompter",
SubTitle:

View File

@@ -153,6 +153,12 @@ const pt: PartialLocaleType = {
Title: "Tamanho da Fonte",
SubTitle: "Ajustar o tamanho da fonte do conteúdo do chat",
},
FontFamily: {
Title: "Fonte do Chat",
SubTitle:
"Fonte do conteúdo do chat, deixe vazio para aplicar a fonte padrão global",
Placeholder: "Nome da Fonte",
},
InjectSystemPrompts: {
Title: "Inserir Prompts de Sistema",
SubTitle: "Inserir um prompt de sistema global para cada requisição",

View File

@@ -71,6 +71,12 @@ const ru: PartialLocaleType = {
Title: "Размер шрифта",
SubTitle: "Настроить размер шрифта контента чата",
},
FontFamily: {
Title: "Шрифт чата",
SubTitle:
"Шрифт содержимого чата, оставьте пустым для применения глобального шрифта по умолчанию",
Placeholder: "Название шрифта",
},
InjectSystemPrompts: {
Title: "Вставить системные подсказки",
SubTitle:

View File

@@ -155,6 +155,12 @@ const sk: PartialLocaleType = {
Title: "Veľkosť písma",
SubTitle: "Nastaviť veľkosť písma obsahu chatu",
},
FontFamily: {
Title: "Chatové Písmo",
SubTitle:
"Písmo obsahu chatu, ponechajte prázdne pre použitie globálneho predvoleného písma",
Placeholder: "Názov Písma",
},
InjectSystemPrompts: {
Title: "Vložiť systémové výzvy",
SubTitle: "Vložiť globálnu systémovú výzvu pre každú požiadavku",

View File

@@ -71,6 +71,12 @@ const tr: PartialLocaleType = {
Title: "Yazı Boyutu",
SubTitle: "Sohbet içeriğinin yazı boyutunu ayarlayın",
},
FontFamily: {
Title: "Sohbet Yazı Tipi",
SubTitle:
"Sohbet içeriğinin yazı tipi, boş bırakıldığında küresel varsayılan yazı tipi uygulanır",
Placeholder: "Yazı Tipi Adı",
},
InjectSystemPrompts: {
Title: "Sistem İpucu Ekleyin",
SubTitle:

View File

@@ -153,6 +153,11 @@ const tw = {
Title: "字型大小",
SubTitle: "聊天內容的字型大小",
},
FontFamily: {
Title: "聊天字體",
SubTitle: "聊天內容的字體,若置空則應用全局默認字體",
Placeholder: "字體名稱",
},
InjectSystemPrompts: {
Title: "匯入系統提示",
SubTitle: "強制在每個請求的訊息列表開頭新增一個模擬 ChatGPT 的系統提示",

View File

@@ -71,6 +71,12 @@ const vi: PartialLocaleType = {
Title: "Font chữ",
SubTitle: "Thay đổi font chữ của nội dung trò chuyện",
},
FontFamily: {
Title: "Phông Chữ Trò Chuyện",
SubTitle:
"Phông chữ của nội dung trò chuyện, để trống để áp dụng phông chữ mặc định toàn cầu",
Placeholder: "Tên Phông Chữ",
},
InjectSystemPrompts: {
Title: "Tiêm Prompt Hệ thống",
SubTitle:

View File

@@ -33,6 +33,7 @@ export const DEFAULT_CONFIG = {
submitKey: SubmitKey.Enter,
avatar: "1f603",
fontSize: 14,
fontFamily: "",
theme: Theme.Auto as Theme,
tightBorder: !!config?.isApp,
sendPreviewBubble: true,

View File

@@ -194,6 +194,7 @@ export function autoGrowTextArea(dom: HTMLTextAreaElement) {
measureDom.style.width = width + "px";
measureDom.innerText = dom.value !== "" ? dom.value : "1";
measureDom.style.fontSize = dom.style.fontSize;
measureDom.style.fontFamily = dom.style.fontFamily;
const endWithEmptyLine = dom.value.endsWith("\n");
const height = parseFloat(window.getComputedStyle(measureDom).height);
const singleLineHeight = parseFloat(

View File

@@ -1,14 +1,17 @@
import { createHash, createHmac } from "node:crypto";
import hash from "hash.js";
// 使用 SHA-256 和 secret 进行 HMAC 加密
function sha256(message: any, secret = "", encoding?: string) {
return createHmac("sha256", secret)
return hash
.hmac(hash.sha256 as any, secret)
.update(message)
.digest(encoding as any);
}
// 使用 SHA-256 进行哈希
function getHash(message: any, encoding = "hex") {
return createHash("sha256")
return hash
.sha256()
.update(message)
.digest(encoding as any);
}