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
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"