Skip to content

Commit

Permalink
Integration with SiliconFlow (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
jackalcooper committed Oct 30, 2024
1 parent d0bd1bf commit ba7dcf9
Show file tree
Hide file tree
Showing 12 changed files with 526 additions and 6 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/auto-rebase.yml
Original file line number Diff line number Diff line change
@@ -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/ChatGPTNextWeb/ChatGPT-Next-Web.git

- name: Fetch upstream changes
run: git fetch upstream

- name: Rebase branch
run: |
git config --global user.email [email protected]
git config --global user.name tsai
git checkout main
git rebase upstream/main
- name: Push changes
run: git push origin main --force
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ For enterprise inquiries, please contact: **[email protected]**
- I18n: English, 简体中文, 繁体中文, 日本語, Français, Español, Italiano, Türkçe, Deutsch, Tiếng Việt, Русский, Čeština, 한국어, Indonesia

<div align="center">

![主界面](./docs/images/cover.png)

</div>
Expand All @@ -102,7 +102,7 @@ For enterprise inquiries, please contact: **[email protected]**

- 🚀 v2.15.4 The Application supports using Tauri fetch LLM API, MORE SECURITY! [#5379](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web/issues/5379)
- 🚀 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.9.11 you can use azure endpoint now.
- 🚀 v2.8 now we have a client that runs across all platforms!
Expand Down Expand Up @@ -154,7 +154,7 @@ For enterprise inquiries, please contact: **[email protected]**
1. Get [OpenAI API Key](https://platform.openai.com/account/api-keys);
2. Click
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.jparrowsec.cn%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.jparrowsec.cn%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 :)

## FAQ
Expand Down Expand Up @@ -348,7 +348,7 @@ Change default model
### `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:
- Each address must be a complete endpoint
- Each address must be a complete endpoint
> `https://xxxx/yyy`
- Multiple addresses are connected by ', '

Expand Down
3 changes: 3 additions & 0 deletions app/api/[provider]/[...path]/route.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { handle as oauthHandler } from "../../oauth_callback";
import { ApiPath } from "@/app/constant";
import { NextRequest } from "next/server";
import { handle as openaiHandler } from "../../openai";
Expand All @@ -20,6 +21,8 @@ async function handle(
const apiPath = `/api/${params.provider}`;
console.log(`[${params.provider} Route] params `, params);
switch (apiPath) {
case ApiPath.OAuth:
return oauthHandler(req, { params });
case ApiPath.Azure:
return azureHandler(req, { params });
case ApiPath.Google:
Expand Down
66 changes: 66 additions & 0 deletions app/api/oauth_callback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
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"
}/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);
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(`/`);
}
91 changes: 91 additions & 0 deletions app/components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import {
DEFAULT_TOPIC,
ModelType,
usePluginStore,
DEFAULT_CONFIG,
} from "../store";

import {
Expand Down Expand Up @@ -114,6 +115,7 @@ import { ExportMessageModal } from "./exporter";
import { getClientConfig } from "../config/client";
import { useAllModels } from "../utils/hooks";
import { MultimodalContent } from "../client/api";
import { useCookies } from "react-cookie";

import { ClientApi } from "../client/api";
import { createTTSPlayer } from "../utils/audio";
Expand Down Expand Up @@ -1247,6 +1249,95 @@ function _Chat() {
return session.mask.hideContext ? [] : session.mask.context.slice();
}, [session.mask.context, session.mask.hideContext]);

const [cookies, setCookie, removeCookie] = useCookies(["sfak"], {
doNotParse: true,
});

const updateDefaultModelConfig = (modelConfig: {
model: any;
providerName: any;
}) => {
const FeaturedModel = "Qwen/Qwen2-7B-Instruct";
if (modelConfig.model == DEFAULT_CONFIG.modelConfig.model) {
modelConfig.model = FeaturedModel as ModelType;
modelConfig.providerName = FeaturedModel as ServiceProvider;
}
};
useEffect(() => {
config.update((config) => {
const ids = [
"Qwen/Qwen2-1.5B-Instruct",
"Qwen/Qwen2-7B-Instruct",
"Qwen/Qwen2.5-7B-Instruct",
"Qwen/Qwen2.5-Coder-7B-Instruct",
"Qwen/Qwen2.5-14B-Instruct",
"Qwen/Qwen2.5-32B-Instruct",
"Qwen/Qwen2-57B-A14B-Instruct",
"Qwen/Qwen2-72B-Instruct",
"Qwen/Qwen2.5-72B-Instruct",
"Qwen/Qwen2.5-Math-72B-Instruct",
"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",
"THUDM/glm-4-9b-chat",
"deepseek-ai/DeepSeek-Coder-V2-Instruct",
"deepseek-ai/DeepSeek-V2-Chat",
"deepseek-ai/DeepSeek-V2.5",
"internlm/internlm2_5-7b-chat",
"internlm/internlm2_5-20b-chat",
"google/gemma-2-9b-it",
"google/gemma-2-27b-it",
"meta-llama/Meta-Llama-3-8B-Instruct",
"meta-llama/Meta-Llama-3.1-8B-Instruct",
"meta-llama/Meta-Llama-3-70B-Instruct",
"meta-llama/Meta-Llama-3.1-70B-Instruct",
"meta-llama/Meta-Llama-3.1-405B-Instruct",
"mistralai/Mistral-7B-Instruct-v0.2",
"Pro/Qwen/Qwen2-1.5B-Instruct",
"Pro/Qwen/Qwen2-7B-Instruct",
"Pro/01-ai/Yi-1.5-6B-Chat",
"Pro/01-ai/Yi-1.5-9B-Chat-16K",
"Pro/THUDM/chatglm3-6b",
"Pro/THUDM/glm-4-9b-chat",
"Pro/internlm/internlm2_5-7b-chat",
"Pro/google/gemma-2-9b-it",
"Pro/meta-llama/Meta-Llama-3-8B-Instruct",
"Pro/meta-llama/Meta-Llama-3.1-8B-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;
updateDefaultModelConfig(config.modelConfig);
});
const sfakValue = cookies.sfak;
if (sfakValue) {
chatStore.updateCurrentSession((session) => {
updateDefaultModelConfig(session.mask.modelConfig);
});
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 ||
"https://api.siliconflow.cn";
});
removeCookie("sfak");
}
}, []);

if (
context.length === 0 &&
session.messages.at(0)?.content !== BOT_HELLO.content
Expand Down
61 changes: 60 additions & 1 deletion app/components/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import styles from "./home.module.scss";
import { IconButton } from "./button";
import SettingsIcon from "../icons/settings.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 AddIcon from "../icons/add.svg";
import DeleteIcon from "../icons/delete.svg";
Expand All @@ -14,7 +16,12 @@ import DiscoveryIcon from "../icons/discovery.svg";

import Locale from "../locales";

import { useAppConfig, useChatStore } from "../store";
import {
DEFAULT_CONFIG,
useAccessStore,
useAppConfig,
useChatStore,
} from "../store";

import {
DEFAULT_SIDEBAR_WIDTH,
Expand All @@ -30,6 +37,7 @@ import { Link, useNavigate } from "react-router-dom";
import { isIOS, useMobileScreen } from "../utils";
import dynamic from "next/dynamic";
import { showConfirm, Selector } from "./ui-lib";
import { useCookies } from "react-cookie";

const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, {
loading: () => null,
Expand Down Expand Up @@ -222,6 +230,10 @@ export function SideBar(props: { className?: string }) {
const navigate = useNavigate();
const config = useAppConfig();
const chatStore = useChatStore();
const accessStore = useAccessStore();
const [cookies, setCookie, removeCookie] = useCookies(["sfak"], {
doNotParse: true,
});

return (
<SideBarContainer
Expand Down Expand Up @@ -314,6 +326,53 @@ export function SideBar(props: { className?: string }) {
/>
</a>
</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={
Expand Down
3 changes: 2 additions & 1 deletion app/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export enum Path {
}

export enum ApiPath {
OAuth = "/api/oauth_callback",
Cors = "",
Azure = "/api/azure",
OpenAI = "/api/openai",
Expand Down Expand Up @@ -239,7 +240,7 @@ You are ChatGPT, a large language model trained by {{ServiceProvider}}.
Knowledge cutoff: {{cutoff}}
Current model: {{model}}
Current time: {{time}}
Latex inline: \\(x^2\\)
Latex inline: \\(x^2\\)
Latex block: $$e=mc^2$$
`;

Expand Down
3 changes: 3 additions & 0 deletions app/icons/sf.active.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions app/icons/sf.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit ba7dcf9

Please sign in to comment.