mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-05-21 23:46:50 +00:00
feat: add i18n support and add Chinese (#372)
* feat: add i18n support and add Chinese * fix: resolve conflicts * Update en.json with cancle settings * Update zh.json with settngs cancle --------- Co-authored-by: johnny0120 <15564476+johnny0120@users.noreply.github.com> Co-authored-by: Willem Jiang <willem.jiang@gmail.com> Co-authored-by: Willem Jiang <143703838+willem-bd@users.noreply.github.com>
This commit is contained in:
@@ -2,17 +2,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
|
||||
import { Welcome } from "./welcome";
|
||||
|
||||
const questions = [
|
||||
"How many times taller is the Eiffel Tower than the tallest building in the world?",
|
||||
"How many years does an average Tesla battery last compared to a gasoline engine?",
|
||||
"How many liters of water are required to produce 1 kg of beef?",
|
||||
"How many times faster is the speed of light compared to the speed of sound?",
|
||||
];
|
||||
export function ConversationStarter({
|
||||
className,
|
||||
onSend,
|
||||
@@ -20,6 +15,9 @@ export function ConversationStarter({
|
||||
className?: string;
|
||||
onSend?: (message: string) => void;
|
||||
}) {
|
||||
const t = useTranslations("chat");
|
||||
const questions = t.raw("conversationStarters") as string[];
|
||||
|
||||
return (
|
||||
<div className={cn("flex flex-col items-center", className)}>
|
||||
<div className="pointer-events-none fixed inset-0 flex items-center justify-center">
|
||||
@@ -41,7 +39,7 @@ export function ConversationStarter({
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="bg-card text-muted-foreground cursor-pointer rounded-2xl border px-4 py-4 opacity-75 transition-all duration-300 hover:opacity-100 hover:shadow-md"
|
||||
className="bg-card text-muted-foreground h-full w-full cursor-pointer rounded-2xl border px-4 py-4 opacity-75 transition-all duration-300 hover:opacity-100 hover:shadow-md"
|
||||
onClick={() => {
|
||||
onSend?.(question);
|
||||
}}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import { MagicWandIcon } from "@radix-ui/react-icons";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { ArrowUp, Lightbulb, X } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useCallback, useMemo, useRef, useState } from "react";
|
||||
|
||||
import { Detective } from "~/components/deer-flow/icons/detective";
|
||||
@@ -46,6 +47,8 @@ export function InputBox({
|
||||
onCancel?: () => void;
|
||||
onRemoveFeedback?: () => void;
|
||||
}) {
|
||||
const t = useTranslations("chat.inputBox");
|
||||
const tCommon = useTranslations("common");
|
||||
const enableDeepThinking = useSettingsStore(
|
||||
(state) => state.general.enableDeepThinking,
|
||||
);
|
||||
@@ -217,12 +220,14 @@ export function InputBox({
|
||||
title={
|
||||
<div>
|
||||
<h3 className="mb-2 font-bold">
|
||||
Deep Thinking Mode: {enableDeepThinking ? "On" : "Off"}
|
||||
{t("deepThinkingTooltip.title", {
|
||||
status: enableDeepThinking ? t("on") : t("off"),
|
||||
})}
|
||||
</h3>
|
||||
<p>
|
||||
When enabled, DeerFlow will use reasoning model (
|
||||
{config.models.reasoning?.[0]}) to generate more thoughtful
|
||||
plans.
|
||||
{t("deepThinkingTooltip.description", {
|
||||
model: config.models.reasoning?.[0] ?? "",
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
@@ -237,7 +242,7 @@ export function InputBox({
|
||||
setEnableDeepThinking(!enableDeepThinking);
|
||||
}}
|
||||
>
|
||||
<Lightbulb /> Deep Thinking
|
||||
<Lightbulb /> {t("deepThinking")}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
@@ -247,13 +252,11 @@ export function InputBox({
|
||||
title={
|
||||
<div>
|
||||
<h3 className="mb-2 font-bold">
|
||||
Investigation Mode: {backgroundInvestigation ? "On" : "Off"}
|
||||
{t("investigationTooltip.title", {
|
||||
status: backgroundInvestigation ? t("on") : t("off"),
|
||||
})}
|
||||
</h3>
|
||||
<p>
|
||||
When enabled, DeerFlow will perform a quick search before
|
||||
planning. This is useful for researches related to ongoing
|
||||
events and news.
|
||||
</p>
|
||||
<p>{t("investigationTooltip.description")}</p>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
@@ -267,13 +270,13 @@ export function InputBox({
|
||||
setEnableBackgroundInvestigation(!backgroundInvestigation)
|
||||
}
|
||||
>
|
||||
<Detective /> Investigation
|
||||
<Detective /> {t("investigation")}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<ReportStyleDialog />
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-2">
|
||||
<Tooltip title="Enhance prompt with AI">
|
||||
<Tooltip title={t("enhancePrompt")}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
@@ -293,7 +296,7 @@ export function InputBox({
|
||||
)}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title={responding ? "Stop" : "Send"}>
|
||||
<Tooltip title={responding ? tCommon("stop") : tCommon("send")}>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
ChevronRight,
|
||||
Lightbulb,
|
||||
} from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import React, { useCallback, useMemo, useRef, useState } from "react";
|
||||
|
||||
import { LoadingAnimation } from "~/components/deer-flow/loading-animation";
|
||||
@@ -252,6 +253,7 @@ function ResearchCard({
|
||||
researchId: string;
|
||||
onToggleResearch?: () => void;
|
||||
}) {
|
||||
const t = useTranslations("chat.research");
|
||||
const reportId = useStore((state) => state.researchReportIds.get(researchId));
|
||||
const hasReport = reportId !== undefined;
|
||||
const reportGenerating = useStore(
|
||||
@@ -260,10 +262,10 @@ function ResearchCard({
|
||||
const openResearchId = useStore((state) => state.openResearchId);
|
||||
const state = useMemo(() => {
|
||||
if (hasReport) {
|
||||
return reportGenerating ? "Generating report..." : "Report generated";
|
||||
return reportGenerating ? t("generatingReport") : t("reportGenerated");
|
||||
}
|
||||
return "Researching...";
|
||||
}, [hasReport, reportGenerating]);
|
||||
return t("researching");
|
||||
}, [hasReport, reportGenerating, t]);
|
||||
const msg = useResearchMessage(researchId);
|
||||
const title = useMemo(() => {
|
||||
if (msg) {
|
||||
@@ -283,8 +285,8 @@ function ResearchCard({
|
||||
<Card className={cn("w-full", className)}>
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
<RainbowText animated={state !== "Report generated"}>
|
||||
{title !== undefined && title !== "" ? title : "Deep Research"}
|
||||
<RainbowText animated={state !== t("reportGenerated")}>
|
||||
{title !== undefined && title !== "" ? title : t("deepResearch")}
|
||||
</RainbowText>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
@@ -297,7 +299,7 @@ function ResearchCard({
|
||||
variant={!openResearchId ? "default" : "outline"}
|
||||
onClick={handleOpen}
|
||||
>
|
||||
{researchId !== openResearchId ? "Open" : "Close"}
|
||||
{researchId !== openResearchId ? t("open") : t("close")}
|
||||
</Button>
|
||||
</div>
|
||||
</CardFooter>
|
||||
@@ -316,6 +318,7 @@ function ThoughtBlock({
|
||||
isStreaming?: boolean;
|
||||
hasMainContent?: boolean;
|
||||
}) {
|
||||
const t = useTranslations("chat.research");
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
|
||||
const [hasAutoCollapsed, setHasAutoCollapsed] = useState(false);
|
||||
@@ -359,7 +362,7 @@ function ThoughtBlock({
|
||||
isStreaming ? "text-primary" : "text-foreground",
|
||||
)}
|
||||
>
|
||||
Deep Thinking
|
||||
{t("deepThinking")}
|
||||
</span>
|
||||
{isStreaming && <LoadingAnimation className="ml-2 scale-75" />}
|
||||
<div className="flex-grow" />
|
||||
@@ -432,6 +435,7 @@ function PlanCard({
|
||||
) => void;
|
||||
waitForFeedback?: boolean;
|
||||
}) {
|
||||
const t = useTranslations("chat.research");
|
||||
const plan = useMemo<{
|
||||
title?: string;
|
||||
thought?: string;
|
||||
@@ -482,7 +486,7 @@ function PlanCard({
|
||||
{`### ${
|
||||
plan.title !== undefined && plan.title !== ""
|
||||
? plan.title
|
||||
: "Deep Research"
|
||||
: t("deepResearch")
|
||||
}`}
|
||||
</Markdown>
|
||||
</CardTitle>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { FastForward, Play } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useCallback, useRef, useState } from "react";
|
||||
|
||||
import { RainbowText } from "~/components/deer-flow/rainbow-text";
|
||||
@@ -27,6 +28,7 @@ import { MessageListView } from "./message-list-view";
|
||||
import { Welcome } from "./welcome";
|
||||
|
||||
export function MessagesBlock({ className }: { className?: string }) {
|
||||
const t = useTranslations("chat.messages");
|
||||
const messageIds = useMessageIds();
|
||||
const messageCount = messageIds.length;
|
||||
const responding = useStore((state) => state.responding);
|
||||
@@ -152,16 +154,16 @@ export function MessagesBlock({ className }: { className?: string }) {
|
||||
<CardHeader className={cn("flex-grow", responding && "pl-3")}>
|
||||
<CardTitle>
|
||||
<RainbowText animated={responding}>
|
||||
{responding ? "Replaying" : `${replayTitle}`}
|
||||
{responding ? t("replaying") : `${replayTitle}`}
|
||||
</RainbowText>
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
<RainbowText animated={responding}>
|
||||
{responding
|
||||
? "DeerFlow is now replaying the conversation..."
|
||||
? t("replayDescription")
|
||||
: replayStarted
|
||||
? "The replay has been stopped."
|
||||
: `You're now in DeerFlow's replay mode. Click the "Play" button on the right to start.`}
|
||||
? t("replayHasStopped")
|
||||
: t("replayModeDescription")}
|
||||
</RainbowText>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
@@ -175,13 +177,13 @@ export function MessagesBlock({ className }: { className?: string }) {
|
||||
onClick={handleFastForwardReplay}
|
||||
>
|
||||
<FastForward size={16} />
|
||||
Fast Forward
|
||||
{t("fastForward")}
|
||||
</Button>
|
||||
)}
|
||||
{!replayStarted && (
|
||||
<Button className="w-24" onClick={handleStartReplay}>
|
||||
<Play size={16} />
|
||||
Play
|
||||
{t("play")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
@@ -190,17 +192,16 @@ export function MessagesBlock({ className }: { className?: string }) {
|
||||
</Card>
|
||||
{!replayStarted && env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY && (
|
||||
<div className="text-muted-foreground w-full text-center text-xs">
|
||||
* This site is for demo purposes only. If you want to try your
|
||||
own question, please{" "}
|
||||
{t("demoNotice")}{" "}
|
||||
<a
|
||||
className="underline"
|
||||
href="https://github.com/bytedance/deer-flow"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
click here
|
||||
{t("clickHere")}
|
||||
</a>{" "}
|
||||
to clone it locally and run it.
|
||||
{t("cloneLocally")}
|
||||
</div>
|
||||
)}
|
||||
</motion.div>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { PythonOutlined } from "@ant-design/icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { LRUCache } from "lru-cache";
|
||||
import { BookOpenText, FileText, PencilRuler, Search } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useTheme } from "next-themes";
|
||||
import { useMemo } from "react";
|
||||
import SyntaxHighlighter from "react-syntax-highlighter";
|
||||
@@ -122,6 +123,7 @@ type SearchResult =
|
||||
};
|
||||
|
||||
function WebSearchToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
|
||||
const t = useTranslations("chat.research");
|
||||
const searching = useMemo(() => {
|
||||
return toolCall.result === undefined;
|
||||
}, [toolCall.result]);
|
||||
@@ -159,7 +161,7 @@ function WebSearchToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
|
||||
animated={searchResults === undefined}
|
||||
>
|
||||
<Search size={16} className={"mr-2"} />
|
||||
<span>Searching for </span>
|
||||
<span>{t("searchingFor")} </span>
|
||||
<span className="max-w-[500px] overflow-hidden text-ellipsis whitespace-nowrap">
|
||||
{(toolCall.args as { query: string }).query}
|
||||
</span>
|
||||
@@ -238,6 +240,7 @@ function WebSearchToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
|
||||
}
|
||||
|
||||
function CrawlToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
|
||||
const t = useTranslations("chat.research");
|
||||
const url = useMemo(
|
||||
() => (toolCall.args as { url: string }).url,
|
||||
[toolCall.args],
|
||||
@@ -251,7 +254,7 @@ function CrawlToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
|
||||
animated={toolCall.result === undefined}
|
||||
>
|
||||
<BookOpenText size={16} className={"mr-2"} />
|
||||
<span>Reading</span>
|
||||
<span>{t("reading")}</span>
|
||||
</RainbowText>
|
||||
</div>
|
||||
<ul className="mt-2 flex flex-wrap gap-4">
|
||||
@@ -279,6 +282,7 @@ function CrawlToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
|
||||
}
|
||||
|
||||
function RetrieverToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
|
||||
const t = useTranslations("chat.research");
|
||||
const searching = useMemo(() => {
|
||||
return toolCall.result === undefined;
|
||||
}, [toolCall.result]);
|
||||
@@ -292,7 +296,7 @@ function RetrieverToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
|
||||
<div className="font-medium italic">
|
||||
<RainbowText className="flex items-center" animated={searching}>
|
||||
<Search size={16} className={"mr-2"} />
|
||||
<span>Retrieving documents from RAG </span>
|
||||
<span>{t("retrievingDocuments")} </span>
|
||||
<span className="max-w-[500px] overflow-hidden text-ellipsis whitespace-nowrap">
|
||||
{(toolCall.args as { keywords: string }).keywords}
|
||||
</span>
|
||||
@@ -337,6 +341,7 @@ function RetrieverToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
|
||||
}
|
||||
|
||||
function PythonToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
|
||||
const t = useTranslations("chat.research");
|
||||
const code = useMemo<string | undefined>(() => {
|
||||
return (toolCall.args as { code?: string }).code;
|
||||
}, [toolCall.args]);
|
||||
@@ -349,7 +354,7 @@ function PythonToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
|
||||
className="text-base font-medium italic"
|
||||
animated={toolCall.result === undefined}
|
||||
>
|
||||
Running Python code
|
||||
{t("runningPythonCode")}
|
||||
</RainbowText>
|
||||
</div>
|
||||
<div>
|
||||
@@ -373,6 +378,7 @@ function PythonToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
|
||||
}
|
||||
|
||||
function PythonToolCallResult({ result }: { result: string }) {
|
||||
const t = useTranslations("chat.research");
|
||||
const { resolvedTheme } = useTheme();
|
||||
const hasError = useMemo(
|
||||
() => result.includes("Error executing code:\n"),
|
||||
@@ -399,7 +405,7 @@ function PythonToolCallResult({ result }: { result: string }) {
|
||||
return (
|
||||
<>
|
||||
<div className="mt-4 font-medium italic">
|
||||
{hasError ? "Error when executing the above code" : "Execution output"}
|
||||
{hasError ? t("errorExecutingCode") : t("executionOutput")}
|
||||
</div>
|
||||
<div className="bg-accent mt-2 max-h-[400px] max-w-[calc(100%-120px)] overflow-y-auto rounded-md p-2 text-sm">
|
||||
<SyntaxHighlighter
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { Check, Copy, Headphones, Pencil, Undo2, X, Download } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { ScrollContainer } from "~/components/deer-flow/scroll-container";
|
||||
@@ -23,6 +24,7 @@ export function ResearchBlock({
|
||||
className?: string;
|
||||
researchId: string | null;
|
||||
}) {
|
||||
const t = useTranslations("chat.research");
|
||||
const reportId = useStore((state) =>
|
||||
researchId ? state.researchReportIds.get(researchId) : undefined,
|
||||
);
|
||||
@@ -108,7 +110,7 @@ export function ResearchBlock({
|
||||
<div className="absolute right-4 flex h-9 items-center justify-center">
|
||||
{hasReport && !reportStreaming && (
|
||||
<>
|
||||
<Tooltip title="Generate podcast">
|
||||
<Tooltip title={t("generatePodcast")}>
|
||||
<Button
|
||||
className="text-gray-400"
|
||||
size="icon"
|
||||
@@ -119,7 +121,7 @@ export function ResearchBlock({
|
||||
<Headphones />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Edit">
|
||||
<Tooltip title={t("edit")}>
|
||||
<Button
|
||||
className="text-gray-400"
|
||||
size="icon"
|
||||
@@ -130,7 +132,7 @@ export function ResearchBlock({
|
||||
{editing ? <Undo2 /> : <Pencil />}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Copy">
|
||||
<Tooltip title={t("copy")}>
|
||||
<Button
|
||||
className="text-gray-400"
|
||||
size="icon"
|
||||
@@ -140,7 +142,7 @@ export function ResearchBlock({
|
||||
{copied ? <Check /> : <Copy />}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Download report as markdown">
|
||||
<Tooltip title={t("downloadReport")}>
|
||||
<Button
|
||||
className="text-gray-400"
|
||||
size="icon"
|
||||
@@ -152,7 +154,7 @@ export function ResearchBlock({
|
||||
</Tooltip>
|
||||
</>
|
||||
)}
|
||||
<Tooltip title="Close">
|
||||
<Tooltip title={t("close")}>
|
||||
<Button
|
||||
className="text-gray-400"
|
||||
size="sm"
|
||||
@@ -177,10 +179,10 @@ export function ResearchBlock({
|
||||
value="report"
|
||||
disabled={!hasReport}
|
||||
>
|
||||
Report
|
||||
{t("report")}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger className="px-8" value="activities">
|
||||
Activities
|
||||
{t("activities")}
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
|
||||
@@ -3,12 +3,16 @@
|
||||
|
||||
import { StarFilledIcon, GitHubLogoIcon } from "@radix-ui/react-icons";
|
||||
import Link from "next/link";
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
import { LanguageSwitcher } from "~/components/deer-flow/language-switcher";
|
||||
import { NumberTicker } from "~/components/magicui/number-ticker";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { env } from "~/env";
|
||||
|
||||
export async function SiteHeader() {
|
||||
export function SiteHeader() {
|
||||
const t = useTranslations('common');
|
||||
|
||||
return (
|
||||
<header className="supports-backdrop-blur:bg-background/80 bg-background/40 sticky top-0 left-0 z-40 flex h-15 w-full flex-col items-center backdrop-blur-lg">
|
||||
<div className="container flex h-15 items-center justify-between px-3">
|
||||
@@ -16,7 +20,8 @@ export async function SiteHeader() {
|
||||
<span className="mr-1 text-2xl">🦌</span>
|
||||
<span>DeerFlow</span>
|
||||
</div>
|
||||
<div className="relative flex items-center">
|
||||
<div className="relative flex items-center gap-2">
|
||||
<LanguageSwitcher />
|
||||
<div
|
||||
className="pointer-events-none absolute inset-0 z-0 h-full w-full rounded-full opacity-60 blur-2xl"
|
||||
style={{
|
||||
@@ -32,7 +37,7 @@ export async function SiteHeader() {
|
||||
>
|
||||
<Link href="https://github.com/bytedance/deer-flow" target="_blank">
|
||||
<GitHubLogoIcon className="size-4" />
|
||||
Star on GitHub
|
||||
{t('starOnGitHub')}
|
||||
{env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY &&
|
||||
env.GITHUB_OAUTH_TOKEN && <StarCounter />}
|
||||
</Link>
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
|
||||
export function Welcome({ className }: { className?: string }) {
|
||||
const t = useTranslations("chat.welcome");
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className={cn("flex flex-col", className)}
|
||||
@@ -13,21 +16,9 @@ export function Welcome({ className }: { className?: string }) {
|
||||
initial={{ opacity: 0, scale: 0.85 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
>
|
||||
<h3 className="mb-2 text-center text-3xl font-medium">
|
||||
👋 Hello, there!
|
||||
</h3>
|
||||
<h3 className="mb-2 text-center text-3xl font-medium">{t("greeting")}</h3>
|
||||
<div className="text-muted-foreground px-4 text-center text-lg">
|
||||
Welcome to{" "}
|
||||
<a
|
||||
href="https://github.com/bytedance/deer-flow"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="hover:underline"
|
||||
>
|
||||
🦌 DeerFlow
|
||||
</a>
|
||||
, a deep research assistant built on cutting-edge language models, helps
|
||||
you search on web, browse information, and handle complex tasks.
|
||||
{t("description")}
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user