diff --git a/web/.env.example b/web/.env.example
index 9d151da..8641b06 100644
--- a/web/.env.example
+++ b/web/.env.example
@@ -14,3 +14,7 @@
# NEXT_PUBLIC_CLIENTVAR="bar"
NEXT_PUBLIC_API_URL=http://localhost:8000/api
+
+# Github
+GITHUB_OAUTH_TOKEN=xxxx
+
diff --git a/web/src/app/chat/components/site-header.tsx b/web/src/app/chat/components/site-header.tsx
new file mode 100644
index 0000000..abfd123
--- /dev/null
+++ b/web/src/app/chat/components/site-header.tsx
@@ -0,0 +1,80 @@
+// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+// SPDX-License-Identifier: MIT
+
+import { StarFilledIcon, GitHubLogoIcon } from "@radix-ui/react-icons";
+import Link from "next/link";
+
+import { Button } from "~/components/ui/button";
+import { env } from "~/env";
+
+export async function SiteHeader() {
+ return (
+
+
+
+ 🦌
+ DeerFlow
+
+
+
+
+
+
+
+
+ );
+}
+
+export async function StarCounter() {
+ let stars = 1000; // Default value
+
+ try {
+ const response = await fetch(
+ "https://api.github.com/repos/bytedance/deer-flow",
+ {
+ headers: env.GITHUB_OAUTH_TOKEN
+ ? {
+ Authorization: `Bearer ${env.GITHUB_OAUTH_TOKEN}`,
+ "Content-Type": "application/json",
+ }
+ : {},
+ next: {
+ revalidate: 3600,
+ },
+ },
+ );
+
+ if (response.ok) {
+ const data = await response.json();
+ stars = data.stargazers_count ?? stars; // Update stars if API response is valid
+ }
+ } catch (error) {
+ console.error("Error fetching GitHub stars:", error);
+ }
+ return (
+ <>
+
+
+ {stars !== null ? stars.toLocaleString() : "—"}
+
+ >
+ );
+}
diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx
index 13591a0..7ca963a 100644
--- a/web/src/app/page.tsx
+++ b/web/src/app/page.tsx
@@ -1,12 +1,9 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
-import { GithubOutlined } from "@ant-design/icons";
-import Link from "next/link";
import { useMemo } from "react";
-import { Button } from "~/components/ui/button";
-
+import { SiteHeader } from "./chat/components/site-header";
import { Jumbotron } from "./landing/components/jumbotron";
import { Ray } from "./landing/components/ray";
import { CaseStudySection } from "./landing/sections/case-study-section";
@@ -17,7 +14,7 @@ import { MultiAgentSection } from "./landing/sections/multi-agent-section";
export default function HomePage() {
return (
-
+
@@ -31,28 +28,6 @@ export default function HomePage() {
);
}
-function Header() {
- return (
-
- );
-}
-
function Footer() {
const year = useMemo(() => new Date().getFullYear(), []);
return (
diff --git a/web/src/env.js b/web/src/env.js
index f6bbf3f..1039193 100644
--- a/web/src/env.js
+++ b/web/src/env.js
@@ -12,6 +12,7 @@ export const env = createEnv({
server: {
NODE_ENV: z.enum(["development", "test", "production"]),
AMPLITUDE_API_KEY: z.string().optional(),
+ GITHUB_OAUTH_TOKEN: z.string().optional(),
},
/**
@@ -34,6 +35,7 @@ export const env = createEnv({
NEXT_PUBLIC_STATIC_WEBSITE_ONLY:
process.env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true",
AMPLITUDE_API_KEY: process.env.AMPLITUDE_API_KEY,
+ GITHUB_OAUTH_TOKEN: process.env.GITHUB_OAUTH_TOKEN,
},
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially