diff --git a/.env.template b/.env.template index d353f535f40..00b5f16e438 100644 --- a/.env.template +++ b/.env.template @@ -77,8 +77,5 @@ HITOKOTO_URL= ###(optional) 侧边栏logo地址,默认是原图标 HEADER_LOGO_URL= -###(optional) 公告,支持markdown语法 -ANNOUNCEMENT="## 新模型 -* grok-beta: 来源XAI,马斯克的大模型。 -* gemini-exp-1114: 来源Google,听说当今第一模型? -" +###(optional) 公告路径,支持markdown语法 +ANNOUNCEMENT_PATH= diff --git a/README.md b/README.md index 3b7b5bd34a2..c807bf7e9bb 100644 --- a/README.md +++ b/README.md @@ -27,5 +27,4 @@ - [one-api](https://github.com/songquanpeng/one-api): 一站式大模型额度管理平台,支持市面上所有主流大语言模型 - [new-api](https://github.com/Calcium-Ion/new-api):在One API的基础上进行二次开发. ## 开源协议 - [MIT](https://opensource.org/license/mit/) diff --git a/app/api/config/route.ts b/app/api/config/route.ts index 1cf2f36b1ec..c7eb6114511 100644 --- a/app/api/config/route.ts +++ b/app/api/config/route.ts @@ -17,7 +17,6 @@ const DANGER_CONFIG = { title: sidebarConfig.title, hitokotoUrl: sidebarConfig.hitokotoUrl, headerLogoUrl: sidebarConfig.headerLogoUrl, - announcement: sidebarConfig.announcement, }; declare global { diff --git a/app/api/readFile/route.ts b/app/api/readFile/route.ts index f17d115ce0e..0a2339e6328 100644 --- a/app/api/readFile/route.ts +++ b/app/api/readFile/route.ts @@ -1,13 +1,17 @@ import fs from "fs/promises"; +import crypto from "crypto"; import { NextResponse } from "next/server"; +function generateHash(input: string) { + return crypto.createHash("sha256").update(input).digest("hex"); +} async function handler(req: any, res: any) { // 定义文件路径 if (process.env.ANNOUNCEMENT_PATH) { const filePath = process.env.ANNOUNCEMENT_PATH; const data = await fs.readFile(filePath, "utf8"); - return NextResponse.json({ content: data }); + return NextResponse.json({ content: data, hash: generateHash(data) }); } - return NextResponse.json({ content: "" }); + return NextResponse.json({ content: "", hash: "" }); } export const GET = handler; export const POST = handler; diff --git a/app/components/chat.tsx b/app/components/chat.tsx index e6f681a8b49..fb3b0e55702 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -939,22 +939,10 @@ export function ShortcutKeyModal(props: { onClose: () => void }) { ); } -export function AnnouncementModal(props: { onClose: () => void }) { - const announcement = useRef(""); - const fetchData = async () => { - const response = await fetch("/api/readFile", { method: "GET" }); - const data = await response.json(); - if (data.content) { - console.log(data.content); - announcement.current = data.content; - } else { - console.error("Failed to fetch file content"); - } - }; - // const { announcement } = useAccessStore(); - useEffect(() => { - fetchData(); - }, []); +export function AnnouncementModal(props: { + announcement: string; + onClose: () => void; +}) { return (
void }) { ]} >
- +
@@ -1655,13 +1643,28 @@ function _Chat() { const [showAnnouncementModal, setShowAnnouncementModal] = useState(false); let hasNewAnnouncement = useRef(false); + const announcement = useRef(""); + const announcementHash = useRef(""); + const localAnnounceHash = useAppConfig().announcementHash; + const refreshAnnouncementHash = useAppConfig().refreshAnnouncementHash; // 通过识别远程和本地公告来在按钮右上角加圆点 - let remoteAnnounce = useAccessStore().announcement; - let localAnnounce = useAppConfig().announcement; - const refreshAnnouncement = useAppConfig().refreshAnnouncement; - if (remoteAnnounce !== localAnnounce) { - hasNewAnnouncement.current = true; - } + const fetchData = async () => { + const response = await fetch("/api/readFile", { method: "GET" }); + const data = await response.json(); + if (data.content) { + announcement.current = data.content; + announcementHash.current = data.hash; + if (data.hash !== localAnnounceHash) { + hasNewAnnouncement.current = true; + refreshAnnouncementHash(announcementHash.current); + } + } else { + console.error("Failed to fetch file content"); + } + }; + useEffect(() => { + fetchData(); + }); return ( <> @@ -1754,7 +1757,6 @@ function _Chat() { onClick={() => { setShowAnnouncementModal(true); hasNewAnnouncement.current = false; - refreshAnnouncement(remoteAnnounce); }} /> @@ -2143,7 +2145,10 @@ function _Chat() { /> )} {showAnnouncementModal && ( - setShowAnnouncementModal(false)} /> + setShowAnnouncementModal(false)} + /> )} {showShortcutKeyModal && ( setShowShortcutKeyModal(false)} /> diff --git a/app/config/server.ts b/app/config/server.ts index c0b69917dc3..73e6cd6dd50 100644 --- a/app/config/server.ts +++ b/app/config/server.ts @@ -84,7 +84,6 @@ declare global { HITOKOTO_URL?: string; SIDEBAR_TITLE?: string; HEADER_LOGO_URL?: string; - ANNOUNCEMENT?: string; ANNOUNCEMENT_PATH?: string; } } @@ -123,7 +122,6 @@ export const getSidebarConfig = () => { title: process.env.SIDEBAR_TITLE ?? "Next Web", hitokotoUrl: process.env.HITOKOTO_URL ?? "https://v1.hitokoto.cn", headerLogoUrl: process.env.HEADER_LOGO_URL ?? "", - announcement: process.env.ANNOUNCEMENT ?? "", }; }; export const getServerSideConfig = () => { diff --git a/app/store/access.ts b/app/store/access.ts index 575c2a2249b..b733ce097d2 100644 --- a/app/store/access.ts +++ b/app/store/access.ts @@ -127,7 +127,6 @@ const DEFAULT_ACCESS_STATE = { title: "", hitokotoUrl: "", headerLogoUrl: "", - announcement: "", // tts config edgeTTSVoiceName: "zh-CN-YunxiNeural", }; diff --git a/app/store/config.ts b/app/store/config.ts index e607fdf86cf..79ff9c21112 100644 --- a/app/store/config.ts +++ b/app/store/config.ts @@ -40,7 +40,7 @@ const config = getClientConfig(); export const DEFAULT_CONFIG = { lastUpdate: Date.now(), // timestamp, to merge state - announcement: "", + announcementHash: "", submitKey: SubmitKey.Enter, avatar: "1f603", fontSize: 14, @@ -62,7 +62,6 @@ export const DEFAULT_CONFIG = { customModels: "", models: DEFAULT_MODELS as any as LLMModel[], - modelConfig: { model: "gpt-4o-mini" as ModelType, providerName: "OpenAI" as ServiceProvider, @@ -167,9 +166,9 @@ export const useAppConfig = createPersistStore( reset() { set(() => ({ ...DEFAULT_CONFIG })); }, - refreshAnnouncement(ann: string) { + refreshAnnouncementHash(hash: string) { set(() => ({ - announcement: ann, + announcementHash: hash, })); }, mergeModels(newModels: LLMModel[]) {