Merge branch 'master' of http://192.168.0.200/knowledge-base-bj/deerflow-server into xuhd
This commit is contained in:
commit
9a67ca7c03
97 files changed
+20759
-306
No files matched your search
@@ -6,7 +6,7 @@ import {
|
||||
type ReactNode,
|
||||
} from "react";
|
||||
|
||||
import { useSidebar } from "@/components/ui/sidebar";
|
||||
import { useSidebarSafe } from "@/components/ui/sidebar";
|
||||
import { env } from "@/env";
|
||||
|
||||
export interface ArtifactsContextType {
|
||||
@@ -39,19 +39,19 @@ export function ArtifactsProvider({ children }: ArtifactsProviderProps) {
|
||||
env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true",
|
||||
);
|
||||
const [autoOpen, setAutoOpen] = useState(true);
|
||||
const { setOpen: setSidebarOpen } = useSidebar();
|
||||
const sidebar = useSidebarSafe();
|
||||
|
||||
const select = useCallback(
|
||||
(artifact: string, autoSelect = false) => {
|
||||
setSelectedArtifact(artifact);
|
||||
if (env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY !== "true") {
|
||||
setSidebarOpen(false);
|
||||
sidebar?.setOpen(false);
|
||||
}
|
||||
if (!autoSelect) {
|
||||
setAutoSelect(false);
|
||||
}
|
||||
},
|
||||
[setSidebarOpen, setSelectedArtifact, setAutoSelect],
|
||||
[sidebar, setSelectedArtifact, setAutoSelect],
|
||||
);
|
||||
|
||||
const deselect = useCallback(() => {
|
||||
|
||||
@@ -80,12 +80,16 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
} from "../ui/dropdown-menu";
|
||||
|
||||
import { useRecommendedQuestions } from "@/core/recommended-questions/hooks";
|
||||
|
||||
|
||||
import { useThread } from "./messages/context";
|
||||
import { ModeHoverGuide } from "./mode-hover-guide";
|
||||
import { Tooltip } from "./tooltip";
|
||||
|
||||
type InputMode = "flash" | "thinking" | "pro" | "ultra";
|
||||
|
||||
|
||||
function getResolvedMode(
|
||||
mode: InputMode | undefined,
|
||||
supportsThinking: boolean,
|
||||
@@ -161,6 +165,8 @@ export function InputBox({
|
||||
null,
|
||||
);
|
||||
|
||||
const { questions: recommendedQuestions } = useRecommendedQuestions();
|
||||
|
||||
useEffect(() => {
|
||||
if (models.length === 0) {
|
||||
return;
|
||||
@@ -430,7 +436,32 @@ export function InputBox({
|
||||
}, [context.model_name, disabled, isMock, status, thread.messages, threadId]);
|
||||
|
||||
return (
|
||||
<div ref={promptRootRef} className="relative flex flex-col gap-4">
|
||||
<div ref={promptRootRef} className="relative flex flex-col gap-6">
|
||||
{extraHeader && (
|
||||
<div className="flex items-center justify-center">
|
||||
{extraHeader}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isNewThread && searchParams.get("mode") !== "skill" && recommendedQuestions.length > 0 && (
|
||||
<div className="flex flex-wrap justify-center gap-2.5 px-4 mb-[10px]">
|
||||
{recommendedQuestions.map((q) => (
|
||||
<button
|
||||
key={q.id}
|
||||
type="button"
|
||||
className="rounded-full border border-[#e4e4e7] bg-white px-4 py-2 text-sm text-[#18181b] shadow-none transition-colors hover:bg-[#f4f4f5] cursor-pointer dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700"
|
||||
onClick={() => {
|
||||
textInput.setInput(q.content);
|
||||
setFollowupsHidden(true);
|
||||
setTimeout(() => requestFormSubmit(), 0);
|
||||
}}
|
||||
>
|
||||
{q.title}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showFollowups && (
|
||||
<div className="flex items-center justify-center pb-2">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -464,7 +495,7 @@ export function InputBox({
|
||||
)}
|
||||
<PromptInput
|
||||
className={cn(
|
||||
"rounded-[1.85rem] border border-[#eadfce] bg-white shadow-[0_24px_70px_-34px_rgba(120,83,42,0.32)] ring-1 ring-[#f6efe5] transition-all duration-300 ease-out *:data-[slot='input-group']:rounded-[1.85rem]",
|
||||
"rounded-[1.85rem] border border-[#eadfce] bg-white shadow-[0_24px_70px_-34px_rgba(120,83,42,0.32)] ring-1 ring-[#f6efe5] transition-all duration-300 ease-out *:data-[slot='input-group']:rounded-[1.85rem] dark:bg-slate-800 dark:border-slate-700 dark:ring-slate-700 dark:shadow-none",
|
||||
className,
|
||||
)}
|
||||
disabled={disabled}
|
||||
@@ -473,20 +504,13 @@ export function InputBox({
|
||||
onSubmit={handleSubmit}
|
||||
{...props}
|
||||
>
|
||||
{extraHeader && (
|
||||
<div className="absolute top-0 right-0 left-0 z-10">
|
||||
<div className="absolute right-0 bottom-0 left-0 flex items-center justify-center">
|
||||
{extraHeader}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<PromptInputAttachments>
|
||||
{(attachment) => <PromptInputAttachment data={attachment} />}
|
||||
</PromptInputAttachments>
|
||||
<PromptInputBody className="absolute top-0 right-0 left-0 z-3">
|
||||
<PromptInputTextarea
|
||||
className={cn(
|
||||
"size-full px-2 py-1 text-[15px] leading-7 placeholder:text-[#b7ab9a]",
|
||||
"size-full px-2 py-1 text-[15px] leading-7 placeholder:text-[#b7ab9a] dark:placeholder:text-slate-500",
|
||||
)}
|
||||
disabled={disabled}
|
||||
placeholder={t.inputBox.placeholder}
|
||||
@@ -494,7 +518,7 @@ export function InputBox({
|
||||
defaultValue={initialValue}
|
||||
/>
|
||||
</PromptInputBody>
|
||||
<PromptInputFooter className="flex items-center border-t border-[#f4ede4] px-2 pt-2.5 pb-1.5">
|
||||
<PromptInputFooter className="flex items-center border-t border-[#f4ede4] dark:border-slate-700 px-2 pt-2.5 pb-1.5">
|
||||
<PromptInputTools className="gap-1.5">
|
||||
{/* TODO: Add more connectors here
|
||||
<PromptInputActionMenu>
|
||||
@@ -505,7 +529,7 @@ export function InputBox({
|
||||
/>
|
||||
</PromptInputActionMenuContent>
|
||||
</PromptInputActionMenu> */}
|
||||
<AddAttachmentsButton className="rounded-full border border-[#eee3d5] bg-[#fffaf5] px-2.5! shadow-none hover:bg-white" />
|
||||
<AddAttachmentsButton className="rounded-full border border-[#eee3d5] bg-[#fffaf5] px-2.5! shadow-none hover:bg-white dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700" />
|
||||
<PromptInputActionMenu>
|
||||
<ModeHoverGuide
|
||||
mode={
|
||||
@@ -517,7 +541,7 @@ export function InputBox({
|
||||
: "flash"
|
||||
}
|
||||
>
|
||||
<PromptInputActionMenuTrigger className="gap-1.5! rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3! text-[#7e6a57] shadow-none hover:bg-white">
|
||||
<PromptInputActionMenuTrigger className="gap-1.5! rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3! text-[#7e6a57] shadow-none hover:bg-white dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700">
|
||||
<div>
|
||||
{context.mode === "flash" && <ZapIcon className="size-3" />}
|
||||
{context.mode === "thinking" && (
|
||||
@@ -679,7 +703,7 @@ export function InputBox({
|
||||
</PromptInputActionMenu>
|
||||
{supportReasoningEffort && context.mode !== "flash" && (
|
||||
<PromptInputActionMenu>
|
||||
<PromptInputActionMenuTrigger className="gap-1.5! rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3! text-[#7e6a57] shadow-none hover:bg-white">
|
||||
<PromptInputActionMenuTrigger className="gap-1.5! rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3! text-[#7e6a57] shadow-none hover:bg-white dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700">
|
||||
<div className="text-xs font-normal">
|
||||
{t.inputBox.reasoningEffort}:
|
||||
{context.reasoning_effort === "minimal" &&
|
||||
@@ -800,7 +824,7 @@ export function InputBox({
|
||||
onOpenChange={setModelDialogOpen}
|
||||
>
|
||||
<ModelSelectorTrigger asChild>
|
||||
<PromptInputButton className="rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3 shadow-none hover:bg-white">
|
||||
<PromptInputButton className="rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3 shadow-none hover:bg-white dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700">
|
||||
<div className="flex min-w-0 flex-col items-start text-left">
|
||||
<ModelSelectorName className="text-xs font-normal">
|
||||
{selectedModel?.display_name}
|
||||
@@ -834,7 +858,7 @@ export function InputBox({
|
||||
</ModelSelectorContent>
|
||||
</ModelSelector>
|
||||
<PromptInputSubmit
|
||||
className="rounded-full border-[#e7d9c7] bg-white shadow-[0_10px_24px_-18px_rgba(120,83,42,0.34)]"
|
||||
className="rounded-full border-[#e7d9c7] bg-white shadow-[0_10px_24px_-18px_rgba(120,83,42,0.34)] dark:bg-blue-500 dark:border-blue-500 dark:text-white dark:hover:bg-blue-400 dark:shadow-none"
|
||||
disabled={disabled}
|
||||
variant="outline"
|
||||
status={status}
|
||||
@@ -842,16 +866,10 @@ export function InputBox({
|
||||
</PromptInputTools>
|
||||
</PromptInputFooter>
|
||||
{!isNewThread && (
|
||||
<div className="absolute right-0 -bottom-[17px] left-0 z-0 h-4 bg-[#fffdfa]"></div>
|
||||
<div className="absolute right-0 -bottom-[17px] left-0 z-0 h-4 bg-[#fffdfa] dark:bg-background"></div>
|
||||
)}
|
||||
</PromptInput>
|
||||
|
||||
{isNewThread && searchParams.get("mode") !== "skill" && (
|
||||
<div className="flex items-center justify-center pt-2">
|
||||
<SuggestionList />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Dialog open={confirmOpen} onOpenChange={setConfirmOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
|
||||
@@ -68,7 +68,7 @@ export function MessageList({
|
||||
<Conversation
|
||||
className={cn("flex size-full flex-col justify-center", className)}
|
||||
>
|
||||
<ConversationContent className="mx-auto w-full max-w-(--container-width-md) gap-8 pt-12">
|
||||
<ConversationContent className="mx-auto w-full max-w-(--container-width-lg) gap-8 pt-12">
|
||||
{groupMessages(messages, (group) => {
|
||||
if (group.type === "human" || group.type === "assistant") {
|
||||
return group.messages.map((msg) => {
|
||||
@@ -454,6 +454,7 @@ function ClarificationCard({
|
||||
const payload = getClarificationPayload(message);
|
||||
const [customAnswer, setCustomAnswer] = useState("");
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
|
||||
const options = useMemo(
|
||||
() =>
|
||||
@@ -473,16 +474,17 @@ function ClarificationCard({
|
||||
);
|
||||
}
|
||||
|
||||
const disabled = isLoading || submitting || !onSubmit;
|
||||
const disabled = false;
|
||||
|
||||
async function submitAnswer(answer: string) {
|
||||
const trimmed = answer.trim();
|
||||
if (!trimmed || disabled) {
|
||||
if (!trimmed) {
|
||||
return;
|
||||
}
|
||||
setSubmitting(true);
|
||||
try {
|
||||
await onSubmit?.(trimmed);
|
||||
setSubmitted(true);
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ function SkeletonBar({
|
||||
export function MessageListSkeleton() {
|
||||
let index = 0;
|
||||
return (
|
||||
<div className="flex w-full max-w-(--container-width-md) flex-col gap-12 p-8 pt-16">
|
||||
<div className="flex w-full max-w-(--container-width-lg) flex-col gap-12 p-8 pt-16">
|
||||
<div
|
||||
role="human-message"
|
||||
className="flex w-[50%] flex-col items-end gap-2 self-end"
|
||||
|
||||
@@ -50,23 +50,23 @@ export function Welcome({
|
||||
</div>
|
||||
{searchParams.get("mode") === "skill" ? (
|
||||
<div className="text-muted-foreground text-sm">
|
||||
{t.welcome.createYourOwnSkillDescription.includes("\n") ? (
|
||||
{/* {t.welcome.createYourOwnSkillDescription.includes("\n") ? (
|
||||
<pre className="font-sans whitespace-pre">
|
||||
{t.welcome.createYourOwnSkillDescription}
|
||||
</pre>
|
||||
) : (
|
||||
<p>{t.welcome.createYourOwnSkillDescription}</p>
|
||||
)}
|
||||
)} */}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-muted-foreground text-sm">
|
||||
{t.welcome.description.includes("\n") ? (
|
||||
{/* {t.welcome.description.includes("\n") ? (
|
||||
<pre className="font-sans whitespace-pre">
|
||||
{t.welcome.description}
|
||||
</pre>
|
||||
) : (
|
||||
<p>{t.welcome.description}</p>
|
||||
)}
|
||||
)} */}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { ChevronsUpDown, Settings2Icon, SettingsIcon } from "lucide-react";
|
||||
import { ChevronsUpDown, MessageSquarePlusIcon, Settings2Icon, SettingsIcon } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import {
|
||||
@@ -17,9 +17,12 @@ import {
|
||||
SidebarMenuItem,
|
||||
useSidebar,
|
||||
} from "@/components/ui/sidebar";
|
||||
import { getStoredAuth } from "@/core/auth";
|
||||
import { useI18n } from "@/core/i18n/hooks";
|
||||
|
||||
import { NotificationBell } from "./notification-bell";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { SettingsDialog } from "./settings";
|
||||
|
||||
function NavMenuButtonContent({
|
||||
@@ -43,9 +46,11 @@ function NavMenuButtonContent({
|
||||
}
|
||||
|
||||
export function WorkspaceNavMenu() {
|
||||
const navigate = useNavigate();
|
||||
const isAdmin = getStoredAuth()?.system_role === "admin";
|
||||
const [settingsOpen, setSettingsOpen] = useState(false);
|
||||
const [settingsDefaultSection, setSettingsDefaultSection] = useState<
|
||||
"appearance" | "memory" | "tools" | "skills" | "notification" | "about"
|
||||
"appearance" | "memory" | "tools" | "notification" | "about"
|
||||
>("appearance");
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const { open: isSidebarOpen } = useSidebar();
|
||||
@@ -92,6 +97,16 @@ export function WorkspaceNavMenu() {
|
||||
<Settings2Icon />
|
||||
{t.common.settings}
|
||||
</DropdownMenuItem>
|
||||
{isAdmin && (
|
||||
<DropdownMenuItem
|
||||
onClick={() =>
|
||||
navigate("/page/workspace/settings/recommended-questions")
|
||||
}
|
||||
>
|
||||
<MessageSquarePlusIcon />
|
||||
推荐问题配置
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
</DropdownMenuContent>
|
||||
|
||||
Reference in new issue
Block a user