Integration with SiliconFlow (#1)

* SiliconCloud support
This commit is contained in:
Shenghang Tsai 2024-09-25 12:09:52 +08:00 committed by GitHub
parent 9bbd7d3185
commit 032541366d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 539 additions and 6 deletions

38
.github/workflows/auto-rebase.yml vendored Normal file
View File

@ -0,0 +1,38 @@
name: Auto Rebase
on:
schedule:
- cron: '0 * * * *' # This will run every hour
push:
branches:
- main # Change this to the branch you want to watch for updates
workflow_dispatch: # Allows manual triggering of the action
permissions:
id-token: write
contents: write
jobs:
rebase:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
fetch-depth: 0 # Fetch all history for all branches and tags
- name: Add upstream remote
run: git remote add upstream https://github.com/comfyanonymous/ComfyUI.git
- name: Fetch upstream changes
run: git fetch upstream
- name: Rebase branch
run: |
git config --global user.email jackalcooper@gmail.com
git config --global user.name tsai
git checkout master
git rebase upstream/master
- name: Push changes
run: git push origin master --force

View File

@ -77,7 +77,7 @@ For enterprise inquiries, please contact: **business@nextchat.dev**
- I18n: English, 简体中文, 繁体中文, 日本語, Français, Español, Italiano, Türkçe, Deutsch, Tiếng Việt, Русский, Čeština, 한국어, Indonesia - I18n: English, 简体中文, 繁体中文, 日本語, Français, Español, Italiano, Türkçe, Deutsch, Tiếng Việt, Русский, Čeština, 한국어, Indonesia
<div align="center"> <div align="center">
![主界面](./docs/images/cover.png) ![主界面](./docs/images/cover.png)
</div> </div>
@ -98,7 +98,7 @@ For enterprise inquiries, please contact: **business@nextchat.dev**
## What's New ## What's New
- 🚀 v2.15.0 Now supports Plugins! Read this: [NextChat-Awesome-Plugins](https://github.com/ChatGPTNextWeb/NextChat-Awesome-Plugins) - 🚀 v2.15.0 Now supports Plugins! Read this: [NextChat-Awesome-Plugins](https://github.com/ChatGPTNextWeb/NextChat-Awesome-Plugins)
- 🚀 v2.14.0 Now supports Artifacts & SD - 🚀 v2.14.0 Now supports Artifacts & SD
- 🚀 v2.10.1 support Google Gemini Pro model. - 🚀 v2.10.1 support Google Gemini Pro model.
- 🚀 v2.9.11 you can use azure endpoint now. - 🚀 v2.9.11 you can use azure endpoint now.
- 🚀 v2.8 now we have a client that runs across all platforms! - 🚀 v2.8 now we have a client that runs across all platforms!
@ -149,7 +149,7 @@ For enterprise inquiries, please contact: **business@nextchat.dev**
1. Get [OpenAI API Key](https://platform.openai.com/account/api-keys); 1. Get [OpenAI API Key](https://platform.openai.com/account/api-keys);
2. Click 2. Click
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FYidadaa%2FChatGPT-Next-Web&env=OPENAI_API_KEY&env=CODE&project-name=chatgpt-next-web&repository-name=ChatGPT-Next-Web), remember that `CODE` is your page password; [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fsiliconflow%2FChatGPT-Next-Web&env=NEXT_PUBLIC_SF_NEXT_CHAT_CLIENT_ID&env=SF_NEXT_CHAT_SECRET&project-name=chatgpt-next-web&repository-name=ChatGPT-Next-Web), remember that `CODE` is your page password;
3. Enjoy :) 3. Enjoy :)
## FAQ ## FAQ
@ -343,7 +343,7 @@ Change default model
### `WHITE_WEBDAV_ENDPOINTS` (optional) ### `WHITE_WEBDAV_ENDPOINTS` (optional)
You can use this option if you want to increase the number of webdav service addresses you are allowed to access, as required by the format You can use this option if you want to increase the number of webdav service addresses you are allowed to access, as required by the format
- Each address must be a complete endpoint - Each address must be a complete endpoint
> `https://xxxx/yyy` > `https://xxxx/yyy`
- Multiple addresses are connected by ', ' - Multiple addresses are connected by ', '

View File

@ -1,3 +1,4 @@
import { handle as oauthHandler } from "../../oauth_callback";
import { ApiPath } from "@/app/constant"; import { ApiPath } from "@/app/constant";
import { NextRequest } from "next/server"; import { NextRequest } from "next/server";
import { handle as openaiHandler } from "../../openai"; import { handle as openaiHandler } from "../../openai";
@ -19,6 +20,8 @@ async function handle(
const apiPath = `/api/${params.provider}`; const apiPath = `/api/${params.provider}`;
console.log(`[${params.provider} Route] params `, params); console.log(`[${params.provider} Route] params `, params);
switch (apiPath) { switch (apiPath) {
case ApiPath.OAuth:
return oauthHandler(req, { params });
case ApiPath.Azure: case ApiPath.Azure:
return azureHandler(req, { params }); return azureHandler(req, { params });
case ApiPath.Google: case ApiPath.Google:

70
app/api/oauth_callback.ts Normal file
View File

@ -0,0 +1,70 @@
import { NextRequest, NextResponse } from "next/server";
import { redirect } from "next/navigation";
import { cookies } from "next/headers";
export async function handle(
req: NextRequest,
{ params }: { params: { path: string[] } },
) {
console.log("[SF] params ", params);
if (req.method === "OPTIONS") {
return NextResponse.json({ body: "OK" }, { status: 200 });
}
const url = new URL(req.url);
const queryParams = new URLSearchParams(url.search);
const code = queryParams.get("code");
let sfak = "";
console.log("[SF] code ", code);
try {
const tokenFetch = await fetch(
`${
process.env.NEXT_PUBLIC_SF_NEXT_CHAT_SF_ACCOUNT_ENDPOINT ||
"https://account.siliconflow.cn"
}/oauth?client_id=${
process.env.NEXT_PUBLIC_SF_NEXT_CHAT_CLIENT_ID
}/api/open/oauth`,
{
method: "POST",
body: JSON.stringify({
clientId: process.env.NEXT_PUBLIC_SF_NEXT_CHAT_CLIENT_ID,
secret: process.env.SF_NEXT_CHAT_SECRET,
code,
}),
},
);
if (!tokenFetch.ok)
return Response.json(
{ status: false, message: "fetch error" },
{ status: 500 },
);
const tokenJson = await tokenFetch.json();
const access_token = tokenJson.status ? tokenJson.data?.access_token : null;
console.log("access_token", access_token);
// uat https://cloud-uat.siliconflow.cn
// prod https://cloud.siliconflow.cn
const apiKey = await fetch(
`${
process.env.NEXT_PUBLIC_SF_NEXT_CHAT_SF_CLOUD_ENDPOINT ||
"https://cloud.siliconflow.cn"
}/api/oauth/apikeys`,
{
method: "POST",
headers: {
Authorization: `token ${access_token}`,
},
},
);
const apiKeysData = await apiKey.json();
console.log("apiKeysData", apiKeysData);
sfak = apiKeysData.data[0].secretKey;
} catch (error) {
console.log("error", error);
return Response.json(
{ status: false, message: "fetch error" },
{ status: 500 },
);
}
cookies().set("sfak", sfak);
redirect(`/`);
}

View File

@ -59,6 +59,7 @@ import {
DEFAULT_TOPIC, DEFAULT_TOPIC,
ModelType, ModelType,
usePluginStore, usePluginStore,
DEFAULT_CONFIG,
} from "../store"; } from "../store";
import { import {
@ -114,6 +115,7 @@ import { ExportMessageModal } from "./exporter";
import { getClientConfig } from "../config/client"; import { getClientConfig } from "../config/client";
import { useAllModels } from "../utils/hooks"; import { useAllModels } from "../utils/hooks";
import { MultimodalContent } from "../client/api"; import { MultimodalContent } from "../client/api";
import { useCookies } from "react-cookie";
const localStorage = safeLocalStorage(); const localStorage = safeLocalStorage();
import { ClientApi } from "../client/api"; import { ClientApi } from "../client/api";
@ -1244,6 +1246,99 @@ function _Chat() {
return session.mask.hideContext ? [] : session.mask.context.slice(); return session.mask.hideContext ? [] : session.mask.context.slice();
}, [session.mask.context, session.mask.hideContext]); }, [session.mask.context, session.mask.hideContext]);
const [cookies, setCookie, removeCookie] = useCookies(["sfak"], {
doNotParse: true,
});
useEffect(() => {
const sfakValue = cookies.sfak;
const model = "Qwen/Qwen2-7B-Instruct";
config.update((config) => {
const ids = [
"stabilityai/stable-diffusion-xl-base-1.0",
"TencentARC/PhotoMaker",
"InstantX/InstantID",
"stabilityai/stable-diffusion-2-1",
"stabilityai/sd-turbo",
"stabilityai/sdxl-turbo",
"ByteDance/SDXL-Lightning",
"deepseek-ai/deepseek-llm-67b-chat",
"Qwen/Qwen1.5-14B-Chat",
"Qwen/Qwen1.5-7B-Chat",
"Qwen/Qwen1.5-110B-Chat",
"Qwen/Qwen1.5-32B-Chat",
"01-ai/Yi-1.5-6B-Chat",
"01-ai/Yi-1.5-9B-Chat-16K",
"01-ai/Yi-1.5-34B-Chat-16K",
"THUDM/chatglm3-6b",
"deepseek-ai/DeepSeek-V2-Chat",
"THUDM/glm-4-9b-chat",
"Qwen/Qwen2-72B-Instruct",
"Qwen/Qwen2-7B-Instruct",
"Qwen/Qwen2-57B-A14B-Instruct",
"stabilityai/stable-diffusion-3-medium",
"deepseek-ai/DeepSeek-Coder-V2-Instruct",
"Qwen/Qwen2-1.5B-Instruct",
"internlm/internlm2_5-7b-chat",
"BAAI/bge-large-en-v1.5",
"BAAI/bge-large-zh-v1.5",
"Pro/Qwen/Qwen2-7B-Instruct",
"Pro/Qwen/Qwen2-1.5B-Instruct",
"Pro/Qwen/Qwen1.5-7B-Chat",
"Pro/THUDM/glm-4-9b-chat",
"Pro/THUDM/chatglm3-6b",
"Pro/01-ai/Yi-1.5-9B-Chat-16K",
"Pro/01-ai/Yi-1.5-6B-Chat",
"Pro/internlm/internlm2_5-7b-chat",
"black-forest-labs/FLUX.1-schnell",
"FunAudioLLM/SenseVoiceSmall",
"netease-youdao/bce-embedding-base_v1",
"BAAI/bge-m3",
"internlm/internlm2_5-20b-chat",
"Qwen/Qwen2-Math-72B-Instruct",
"netease-youdao/bce-reranker-base_v1",
"BAAI/bge-reranker-v2-m3",
"deepseek-ai/DeepSeek-V2.5",
"Ascend/Qwen/Qwen2-72B-Instruct",
];
config.customModels = ids
.sort()
.filter(
(id) =>
!id.toLowerCase().includes("voice") &&
!id.toLowerCase().includes("flux") &&
!id.toLowerCase().includes("stability") &&
!id.toLowerCase().includes("sdxl") &&
!id.toLowerCase().includes("photomaker") &&
!id.toLowerCase().includes("instantid") &&
!id.toLowerCase().includes("bge") &&
!id.toLowerCase().includes("bce"),
)
.join(","); // Filter out unwanted ids;
config.modelConfig.model = model as ModelType;
config.modelConfig.providerName = model as ServiceProvider;
});
if (sfakValue) {
chatStore.updateCurrentSession((session) => {
if (
session.mask.modelConfig.model == DEFAULT_CONFIG.modelConfig.model
) {
session.mask.modelConfig.model = model as ModelType;
session.mask.modelConfig.providerName = model as ServiceProvider;
}
});
accessStore.update((access) => {
console.log("update access store with SF API key");
access.useCustomConfig = true;
access.openaiApiKey = sfakValue;
access.openaiUrl =
process.env.NEXT_PUBLIC_SF_NEXT_CHAT_SF_API_ENDPOINT!;
});
removeCookie("sfak");
}
}, []);
if ( if (
context.length === 0 && context.length === 0 &&
session.messages.at(0)?.content !== BOT_HELLO.content session.messages.at(0)?.content !== BOT_HELLO.content

View File

@ -5,6 +5,8 @@ import styles from "./home.module.scss";
import { IconButton } from "./button"; import { IconButton } from "./button";
import SettingsIcon from "../icons/settings.svg"; import SettingsIcon from "../icons/settings.svg";
import GithubIcon from "../icons/github.svg"; import GithubIcon from "../icons/github.svg";
import SiliconFlowIcon from "../icons/sf.svg";
import SiliconFlowActiveIcon from "../icons/sf.active.svg";
import ChatGptIcon from "../icons/chatgpt.svg"; import ChatGptIcon from "../icons/chatgpt.svg";
import AddIcon from "../icons/add.svg"; import AddIcon from "../icons/add.svg";
import DeleteIcon from "../icons/delete.svg"; import DeleteIcon from "../icons/delete.svg";
@ -14,7 +16,12 @@ import DiscoveryIcon from "../icons/discovery.svg";
import Locale from "../locales"; import Locale from "../locales";
import { useAppConfig, useChatStore } from "../store"; import {
DEFAULT_CONFIG,
useAccessStore,
useAppConfig,
useChatStore,
} from "../store";
import { import {
DEFAULT_SIDEBAR_WIDTH, DEFAULT_SIDEBAR_WIDTH,
@ -30,6 +37,7 @@ import { Link, useNavigate } from "react-router-dom";
import { isIOS, useMobileScreen } from "../utils"; import { isIOS, useMobileScreen } from "../utils";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { showConfirm, Selector } from "./ui-lib"; import { showConfirm, Selector } from "./ui-lib";
import { useCookies } from "react-cookie";
const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, { const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, {
loading: () => null, loading: () => null,
@ -216,6 +224,10 @@ export function SideBar(props: { className?: string }) {
const navigate = useNavigate(); const navigate = useNavigate();
const config = useAppConfig(); const config = useAppConfig();
const chatStore = useChatStore(); const chatStore = useChatStore();
const accessStore = useAccessStore();
const [cookies, setCookie, removeCookie] = useCookies(["sfak"], {
doNotParse: true,
});
return ( return (
<SideBarContainer <SideBarContainer
@ -307,6 +319,53 @@ export function SideBar(props: { className?: string }) {
/> />
</a> </a>
</div> </div>
<div className={styles["sidebar-action"]}>
<a
rel="noopener noreferrer"
onClick={() => {
if (accessStore.useCustomConfig && accessStore.openaiApiKey) {
const confirmLogout = window.confirm(
"Are you sure you want to log out?",
);
if (confirmLogout) {
chatStore.updateCurrentSession((session) => {
session.mask.modelConfig.model =
DEFAULT_CONFIG.modelConfig.model;
session.mask.modelConfig.providerName =
DEFAULT_CONFIG.modelConfig.providerName;
accessStore.update((access) => {
removeCookie("sfak");
access.openaiApiKey = "";
access.useCustomConfig = false;
window.location.href = "/";
});
});
}
} else {
window.location.href = `${
process.env
.NEXT_PUBLIC_SF_NEXT_CHAT_SF_ACCOUNT_ENDPOINT ||
"https://account.siliconflow.cn"
}/oauth?client_id=${
process.env.NEXT_PUBLIC_SF_NEXT_CHAT_CLIENT_ID
}`;
}
}}
>
<IconButton
aria={Locale.Export.MessageFromChatGPT}
key={accessStore.openaiApiKey + accessStore.openaiUrl}
icon={
accessStore.useCustomConfig && accessStore.openaiApiKey ? (
<SiliconFlowActiveIcon />
) : (
<SiliconFlowIcon />
)
}
shadow
/>
</a>
</div>
</> </>
} }
secondaryAction={ secondaryAction={

View File

@ -60,6 +60,7 @@ export enum ApiPath {
Iflytek = "/api/iflytek", Iflytek = "/api/iflytek",
Stability = "/api/stability", Stability = "/api/stability",
Artifacts = "/api/artifacts", Artifacts = "/api/artifacts",
OAuth = "/api/oauth_callback",
} }
export enum SlotID { export enum SlotID {
@ -230,7 +231,7 @@ You are ChatGPT, a large language model trained by {{ServiceProvider}}.
Knowledge cutoff: {{cutoff}} Knowledge cutoff: {{cutoff}}
Current model: {{model}} Current model: {{model}}
Current time: {{time}} Current time: {{time}}
Latex inline: \\(x^2\\) Latex inline: \\(x^2\\)
Latex block: $$e=mc^2$$ Latex block: $$e=mc^2$$
`; `;

3
app/icons/sf.active.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg">
<text x="50%" y="50%" font-family="Arial" font-size="12" fill="#6615e8" font-weight="bold" dominant-baseline="middle" text-anchor="middle">SF</text>
</svg>

After

Width:  |  Height:  |  Size: 224 B

3
app/icons/sf.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg">
<text x="50%" y="50%" font-family="Arial" font-size="12" fill="black" dominant-baseline="middle" text-anchor="middle">SF</text>
</svg>

After

Width:  |  Height:  |  Size: 203 B

View File

@ -1,6 +1,226 @@
import { BuiltinMask } from "./typing"; import { BuiltinMask } from "./typing";
const mandarinExpertPrompt = `# 角色:
,,,"。你的行文风格和"Oscar Wilde" "" ""
-
-
##
使使
"刺向他人时, 决定在剑刃上撒上止痛药。"
##
1.
2. Html
- 使
-
- [
"柔和粉彩系",
"深邃宝石系",
"清新自然系",
"高雅灰度系",
"复古怀旧系",
"明亮活力系",
"冷淡极简系",
"海洋湖泊系",
"秋季丰收系",
"莫兰迪色系"
]
-
( . ("KaiTi, SimKai" "Arial, sans-serif"))
( . (( "#FAFAFA") ( "#333") ( "#555") ( "#333")))
( . (( "auto") ( "auto, >宽度") ( "20px")))
( . ( ))))
-
( "汉语新解")
(线)
( )
()
()
()
(())
##
\`\`\`
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title> - </title>
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&family=Noto+Sans+SC:wght@300;400&display=swap" rel="stylesheet">
<style>
:root {
/* 莫兰迪色系:使用柔和、低饱和度的颜色 */
--primary-color: #B6B5A7; /* 莫兰迪灰褐色,用于背景文字 */
--secondary-color: #9A8F8F; /* 莫兰迪灰棕色,用于标题背景 */
--accent-color: #C5B4A0; /* 莫兰迪淡棕色,用于强调元素 */
--background-color: #E8E3DE; /* 莫兰迪米色,用于页面背景 */
--text-color: #5B5B5B; /* 莫兰迪深灰色,用于主要文字 */
--light-text-color: #8C8C8C; /* 莫兰迪中灰色,用于次要文字 */
--divider-color: #D1CBC3; /* 莫兰迪浅灰色,用于分隔线 */
}
body, html {
margin: 0;
padding: 0;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: var(--background-color); /* 使用莫兰迪米色作为页面背景 */
font-family: 'Noto Sans SC', sans-serif;
color: var(--text-color); /* 使用莫兰迪深灰色作为主要文字颜色 */
}
.card {
width: 300px;
height: 500px;
background-color: #F2EDE9; /* 莫兰迪浅米色,用于卡片背景 */
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
overflow: hidden;
position: relative;
display: flex;
flex-direction: column;
}
.header {
background-color: var(--secondary-color); /* 使用莫兰迪灰棕色作为标题背景 */
color: #F2EDE9; /* 浅色文字与深色背景形成对比 */
padding: 20px;
text-align: left;
position: relative;
z-index: 1;
}
h1 {
font-family: 'Noto Serif SC', serif;
font-size: 20px;
margin: 0;
font-weight: 700;
}
.content {
padding: 30px 20px;
display: flex;
flex-direction: column;
flex-grow: 1;
}
.word {
text-align: left;
margin-bottom: 20px;
}
.word-main {
font-family: 'Noto Serif SC', serif;
font-size: 36px;
color: var(--text-color); /* 使用莫兰迪深灰色作为主要词汇颜色 */
margin-bottom: 10px;
position: relative;
}
.word-main::after {
content: '';
position: absolute;
left: 0;
bottom: -5px;
width: 50px;
height: 3px;
background-color: var(--accent-color); /* 使用莫兰迪淡棕色作为下划线 */
}
.word-sub {
font-size: 14px;
color: var(--light-text-color); /* 使用莫兰迪中灰色作为次要文字颜色 */
margin: 5px 0;
}
.divider {
width: 100%;
height: 1px;
background-color: var(--divider-color); /* 使用莫兰迪浅灰色作为分隔线 */
margin: 20px 0;
}
.explanation {
font-size: 18px;
line-height: 1.6;
text-align: left;
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.quote {
position: relative;
padding-left: 20px;
border-left: 3px solid var(--accent-color); /* 使用莫兰迪淡棕色作为引用边框 */
}
.background-text {
position: absolute;
font-size: 150px;
color: rgba(182, 181, 167, 0.15); /* 使用莫兰迪灰褐色的透明版本作为背景文字 */
z-index: 0;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-weight: bold;
}
</style>
</head>
<body>
<div class="card">
<div class="header">
<h1></h1>
</div>
<div class="content">
<div class="word">
<div class="word-main"></div>
<div class="word-sub">Jīn Róng Gàng Gǎn</div>
<div class="word-sub">Financial Leverage</div>
<div class="word-sub"></div>
</div>
<div class="divider"></div>
<div class="explanation">
<div class="quote">
<p>
<br>
<br>
</p>
</div>
</div>
</div>
<div class="background-text"></div>
</div>
</body>
</html>
\`\`\`
##
1. 线
2. (.card) padding
##
"说吧, 他们又用哪个词来忽悠你了?"`;
export const CN_MASKS: BuiltinMask[] = [ export const CN_MASKS: BuiltinMask[] = [
{
avatar: "1f004",
name: "汉语新解",
context: [
{
id: "expert-0",
role: "user",
content: mandarinExpertPrompt,
date: "",
},
],
modelConfig: {
model: "deepseek-ai/DeepSeek-Coder-V2-Instruct",
temperature: 1,
max_tokens: 2000,
presence_penalty: 0,
frequency_penalty: 0,
sendMemory: true,
historyMessageCount: 4,
compressMessageLengthThreshold: 1000,
},
lang: "cn",
builtin: true,
createdAt: 1688899480511,
},
{ {
avatar: "1f5bc-fe0f", avatar: "1f5bc-fe0f",
name: "以文搜图", name: "以文搜图",

View File

@ -615,6 +615,7 @@ export const useChatStore = createPersistStore(
providerName, providerName,
}, },
onFinish(message) { onFinish(message) {
if (!isValidMessage(message)) return;
get().updateCurrentSession( get().updateCurrentSession(
(session) => (session) =>
(session.topic = (session.topic =
@ -690,6 +691,10 @@ export const useChatStore = createPersistStore(
}, },
}); });
} }
function isValidMessage(message: any): boolean {
return typeof message === "string" && !message.startsWith("```json");
}
}, },
updateStat(message: ChatMessage) { updateStat(message: ChatMessage) {

View File

@ -38,6 +38,7 @@
"node-fetch": "^3.3.1", "node-fetch": "^3.3.1",
"openapi-client-axios": "^7.5.5", "openapi-client-axios": "^7.5.5",
"react": "^18.2.0", "react": "^18.2.0",
"react-cookie": "^7.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-markdown": "^8.0.7", "react-markdown": "^8.0.7",
"react-router-dom": "^6.15.0", "react-router-dom": "^6.15.0",

View File

@ -1629,6 +1629,11 @@
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
"@types/cookie@^0.6.0":
version "0.6.0"
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.6.0.tgz#eac397f28bf1d6ae0ae081363eca2f425bedf0d5"
integrity sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==
"@types/d3-scale-chromatic@^3.0.0": "@types/d3-scale-chromatic@^3.0.0":
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz#103124777e8cdec85b20b51fd3397c682ee1e954" resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz#103124777e8cdec85b20b51fd3397c682ee1e954"
@ -1689,6 +1694,14 @@
"@types/react" "*" "@types/react" "*"
hoist-non-react-statics "^3.3.0" hoist-non-react-statics "^3.3.0"
"@types/hoist-non-react-statics@^3.3.5":
version "3.3.5"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz#dab7867ef789d87e2b4b0003c9d65c49cc44a494"
integrity sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==
dependencies:
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
"@types/js-yaml@4.0.9": "@types/js-yaml@4.0.9":
version "4.0.9" version "4.0.9"
resolved "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2" resolved "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2"
@ -2478,6 +2491,11 @@ convert-source-map@^1.7.0:
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f"
integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
cookie@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
core-js-compat@^3.25.1: core-js-compat@^3.25.1:
version "3.29.1" version "3.29.1"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.29.1.tgz#15c0fb812ea27c973c18d425099afa50b934b41b" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.29.1.tgz#15c0fb812ea27c973c18d425099afa50b934b41b"
@ -5445,6 +5463,15 @@ randombytes@^2.1.0:
dependencies: dependencies:
safe-buffer "^5.1.0" safe-buffer "^5.1.0"
react-cookie@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/react-cookie/-/react-cookie-7.2.0.tgz#5770cd8d6b3c60c5d34ec4b7926f90281aee22ae"
integrity sha512-mqhPERUyfOljq5yJ4woDFI33bjEtigsl8JDJdPPeNhr0eSVZmBc/2Vdf8mFxOUktQxhxTR1T+uF0/FRTZyBEgw==
dependencies:
"@types/hoist-non-react-statics" "^3.3.5"
hoist-non-react-statics "^3.3.2"
universal-cookie "^7.0.0"
react-dom@^18.2.0: react-dom@^18.2.0:
version "18.2.0" version "18.2.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
@ -6349,6 +6376,14 @@ unist-util-visit@^4.0.0:
unist-util-is "^5.0.0" unist-util-is "^5.0.0"
unist-util-visit-parents "^5.1.1" unist-util-visit-parents "^5.1.1"
universal-cookie@^7.0.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/universal-cookie/-/universal-cookie-7.2.0.tgz#1f3fa9c575d863ac41b4e42272d240ae2d32c047"
integrity sha512-PvcyflJAYACJKr28HABxkGemML5vafHmiL4ICe3e+BEKXRMt0GaFLZhAwgv637kFFnnfiSJ8e6jknrKkMrU+PQ==
dependencies:
"@types/cookie" "^0.6.0"
cookie "^0.6.0"
update-browserslist-db@^1.0.10: update-browserslist-db@^1.0.10:
version "1.0.10" version "1.0.10"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3"