mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-10-01 15:46:39 +08:00
parent
9bbd7d3185
commit
032541366d
38
.github/workflows/auto-rebase.yml
vendored
Normal file
38
.github/workflows/auto-rebase.yml
vendored
Normal 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
|
@ -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">
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
</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
|
||||||
[](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;
|
[](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 ', '
|
||||||
|
|
||||||
|
@ -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
70
app/api/oauth_callback.ts
Normal 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(`/`);
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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={
|
||||||
|
@ -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
3
app/icons/sf.active.svg
Normal 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
3
app/icons/sf.svg
Normal 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 |
220
app/masks/cn.ts
220
app/masks/cn.ts
@ -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: "以文搜图",
|
||||||
|
@ -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) {
|
||||||
|
@ -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",
|
||||||
|
35
yarn.lock
35
yarn.lock
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user