mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-01-27 13:46:39 +08:00
Feat: Add a web search button to the chat box on the chat page. (#12786)
### What problem does this PR solve? Feat: Add a web search button to the chat box on the chat page. ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -934,6 +934,7 @@ async def chatbots_inputs(dialog_id):
|
||||
"title": dialog.name,
|
||||
"avatar": dialog.icon,
|
||||
"prologue": dialog.prompt_config.get("prologue", ""),
|
||||
"has_tavily_key": bool(dialog.prompt_config.get("tavily_api_key", "").strip()),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@ -268,7 +268,7 @@ const FloatingChatWidget = () => {
|
||||
|
||||
// Wait for state to update, then send
|
||||
setTimeout(() => {
|
||||
handlePressEnter({ enableThinking: false });
|
||||
handlePressEnter({ enableThinking: false, enableInternet: false });
|
||||
// Clear our local input after sending
|
||||
setInputValue('');
|
||||
}, 50);
|
||||
|
||||
@ -16,7 +16,15 @@ import { Button } from '@/components/ui/button';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { t } from 'i18next';
|
||||
import { CircleStop, Paperclip, Send, Upload, X } from 'lucide-react';
|
||||
import {
|
||||
Atom,
|
||||
CircleStop,
|
||||
Globe,
|
||||
Paperclip,
|
||||
Send,
|
||||
Upload,
|
||||
X,
|
||||
} from 'lucide-react';
|
||||
import * as React from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
@ -32,13 +40,20 @@ interface NextMessageInputProps {
|
||||
isShared?: boolean;
|
||||
showUploadIcon?: boolean;
|
||||
isUploading?: boolean;
|
||||
onPressEnter({ enableThinking }: { enableThinking: boolean }): void;
|
||||
onPressEnter({
|
||||
enableThinking,
|
||||
enableInternet,
|
||||
}: {
|
||||
enableThinking: boolean;
|
||||
enableInternet: boolean;
|
||||
}): void;
|
||||
onInputChange: React.ChangeEventHandler<HTMLTextAreaElement>;
|
||||
createConversationBeforeUploadDocument?(message: string): Promise<any>;
|
||||
stopOutputMessage?(): void;
|
||||
onUpload?: NonNullable<FileUploadProps['onUpload']>;
|
||||
removeFile?(file: File): void;
|
||||
showReasoning?: boolean;
|
||||
showInternet?: boolean;
|
||||
}
|
||||
|
||||
export type NextMessageInputOnPressEnterParameter = Parameters<
|
||||
@ -58,6 +73,7 @@ export function NextMessageInput({
|
||||
onPressEnter,
|
||||
removeFile,
|
||||
showReasoning = false,
|
||||
showInternet = false,
|
||||
}: NextMessageInputProps) {
|
||||
const [files, setFiles] = React.useState<File[]>([]);
|
||||
const [audioInputValue, setAudioInputValue] = React.useState<string | null>(
|
||||
@ -65,11 +81,23 @@ export function NextMessageInput({
|
||||
);
|
||||
|
||||
const [enableThinking, setEnableThinking] = useState(false);
|
||||
const [enableInternet, setEnableInternet] = useState(false);
|
||||
|
||||
const handleThinkingToggle = useCallback(() => {
|
||||
setEnableThinking((prev) => !prev);
|
||||
}, []);
|
||||
|
||||
const handleInternetToggle = useCallback(() => {
|
||||
setEnableInternet((prev) => !prev);
|
||||
}, []);
|
||||
|
||||
const pressEnter = useCallback(() => {
|
||||
onPressEnter({
|
||||
enableThinking,
|
||||
enableInternet: showInternet ? enableInternet : false,
|
||||
});
|
||||
}, [onPressEnter, enableThinking, enableInternet, showInternet]);
|
||||
|
||||
useEffect(() => {
|
||||
if (audioInputValue !== null) {
|
||||
onInputChange({
|
||||
@ -77,11 +105,19 @@ export function NextMessageInput({
|
||||
} as React.ChangeEvent<HTMLTextAreaElement>);
|
||||
|
||||
setTimeout(() => {
|
||||
onPressEnter({ enableThinking });
|
||||
pressEnter();
|
||||
setAudioInputValue(null);
|
||||
}, 0);
|
||||
}
|
||||
}, [audioInputValue, onInputChange, onPressEnter, enableThinking]);
|
||||
}, [
|
||||
audioInputValue,
|
||||
onInputChange,
|
||||
onPressEnter,
|
||||
enableThinking,
|
||||
enableInternet,
|
||||
showInternet,
|
||||
pressEnter,
|
||||
]);
|
||||
|
||||
const onFileReject = React.useCallback((file: File, message: string) => {
|
||||
toast(message, {
|
||||
@ -91,9 +127,9 @@ export function NextMessageInput({
|
||||
|
||||
const submit = React.useCallback(() => {
|
||||
if (isUploading) return;
|
||||
onPressEnter({ enableThinking });
|
||||
pressEnter();
|
||||
setFiles([]);
|
||||
}, [isUploading, onPressEnter, enableThinking]);
|
||||
}, [isUploading, pressEnter]);
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
@ -205,9 +241,25 @@ export function NextMessageInput({
|
||||
)}
|
||||
onClick={handleThinkingToggle}
|
||||
>
|
||||
<Atom />
|
||||
<span>Thinking</span>
|
||||
</Button>
|
||||
)}
|
||||
{showInternet && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
className={cn(
|
||||
'rounded-sm h-7 focus-visible:bg-none! hover:bg-none!',
|
||||
{
|
||||
'bg-accent-primary text-white': enableInternet,
|
||||
},
|
||||
)}
|
||||
onClick={handleInternetToggle}
|
||||
>
|
||||
<Globe />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
{sendLoading ? (
|
||||
<Button onClick={stopOutputMessage} className="size-5 rounded-sm">
|
||||
|
||||
@ -13,6 +13,7 @@ export interface PromptConfig {
|
||||
use_kg: boolean;
|
||||
reasoning?: boolean;
|
||||
cross_languages?: Array<string>;
|
||||
tavily_api_key?: string;
|
||||
}
|
||||
|
||||
export interface Parameter {
|
||||
@ -100,6 +101,7 @@ export interface Message {
|
||||
chatBoxId?: string;
|
||||
attachment?: IAttachment;
|
||||
reasoning?: boolean;
|
||||
internet?: boolean;
|
||||
}
|
||||
|
||||
export interface IReferenceChunk {
|
||||
@ -183,6 +185,7 @@ export interface IExternalChatInfo {
|
||||
avatar?: string;
|
||||
title: string;
|
||||
prologue?: string;
|
||||
has_tavily_key?: boolean;
|
||||
}
|
||||
|
||||
export interface IMessage extends Message {
|
||||
|
||||
@ -291,6 +291,7 @@ export const useSendAgentMessage = ({
|
||||
|
||||
params.session_id = sessionId;
|
||||
params.reasoning = message.reasoning;
|
||||
params.internet = message.internet;
|
||||
}
|
||||
|
||||
try {
|
||||
@ -358,13 +359,21 @@ export const useSendAgentMessage = ({
|
||||
]);
|
||||
|
||||
const handlePressEnter = useCallback(
|
||||
(...[{ enableThinking }]: NextMessageInputOnPressEnterParameter) => {
|
||||
(
|
||||
...[
|
||||
{ enableThinking, enableInternet },
|
||||
]: NextMessageInputOnPressEnterParameter
|
||||
) => {
|
||||
if (trim(value) === '') return;
|
||||
const msgBody = buildRequestBody(value);
|
||||
if (done) {
|
||||
setValue('');
|
||||
sendMessage({
|
||||
message: { ...msgBody, reasoning: enableThinking },
|
||||
message: {
|
||||
...msgBody,
|
||||
reasoning: enableThinking,
|
||||
internet: enableInternet,
|
||||
},
|
||||
});
|
||||
}
|
||||
addNewestOneQuestion({ ...msgBody, files: fileList });
|
||||
|
||||
@ -39,6 +39,7 @@ import { useSendMessage } from '../../hooks/use-send-chat-message';
|
||||
import { useSendMultipleChatMessage } from '../../hooks/use-send-multiple-message';
|
||||
import { buildMessageItemReference } from '../../utils';
|
||||
import { useAddChatBox } from '../use-add-box';
|
||||
import { useShowInternet } from '../use-show-internet';
|
||||
import { useSetDefaultModel } from './use-set-default-model';
|
||||
|
||||
type MultipleChatBoxProps = {
|
||||
@ -226,6 +227,8 @@ export function MultipleChatBox({
|
||||
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
||||
useClickDrawer();
|
||||
|
||||
const showInternet = useShowInternet();
|
||||
|
||||
return (
|
||||
<section className="h-full flex flex-col px-5">
|
||||
<div className="flex gap-4 flex-1 px-5 pb-14 min-h-0">
|
||||
@ -261,6 +264,7 @@ export function MultipleChatBox({
|
||||
stopOutputMessage={stopOutputMessage}
|
||||
onUpload={handleUploadFile}
|
||||
showReasoning
|
||||
showInternet={showInternet}
|
||||
/>
|
||||
</div>
|
||||
{visible && (
|
||||
|
||||
@ -18,6 +18,7 @@ import {
|
||||
import { useCreateConversationBeforeUploadDocument } from '../../hooks/use-create-conversation';
|
||||
import { useSendMessage } from '../../hooks/use-send-chat-message';
|
||||
import { buildMessageItemReference } from '../../utils';
|
||||
import { useShowInternet } from '../use-show-internet';
|
||||
|
||||
interface IProps {
|
||||
controller: AbortController;
|
||||
@ -55,6 +56,8 @@ export function SingleChatBox({
|
||||
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
||||
useClickDrawer();
|
||||
|
||||
const showInternet = useShowInternet();
|
||||
|
||||
useEffect(() => {
|
||||
const messages = conversation?.message;
|
||||
if (Array.isArray(messages)) {
|
||||
@ -120,6 +123,7 @@ export function SingleChatBox({
|
||||
isUploading={isUploading}
|
||||
removeFile={removeFile}
|
||||
showReasoning
|
||||
showInternet={showInternet}
|
||||
/>
|
||||
{visible && (
|
||||
<PdfSheet
|
||||
|
||||
8
web/src/pages/next-chats/chat/use-show-internet.ts
Normal file
8
web/src/pages/next-chats/chat/use-show-internet.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { useFetchDialog } from '@/hooks/use-chat-request';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
export function useShowInternet() {
|
||||
const { data: currentDialog } = useFetchDialog();
|
||||
|
||||
return !isEmpty(currentDialog?.prompt_config?.tavily_api_key);
|
||||
}
|
||||
@ -135,7 +135,11 @@ export const useSendMessage = (controller: AbortController) => {
|
||||
useCreateConversationBeforeSendMessage();
|
||||
|
||||
const handlePressEnter = useCallback(
|
||||
async (...[{ enableThinking }]: NextMessageInputOnPressEnterParameter) => {
|
||||
async (
|
||||
...[
|
||||
{ enableThinking, enableInternet },
|
||||
]: NextMessageInputOnPressEnterParameter
|
||||
) => {
|
||||
if (trim(value) === '') return;
|
||||
|
||||
const data = await createConversationBeforeSendMessage(value);
|
||||
@ -168,6 +172,7 @@ export const useSendMessage = (controller: AbortController) => {
|
||||
files: files,
|
||||
conversationId: targetConversationId,
|
||||
reasoning: enableThinking,
|
||||
internet: enableInternet,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -177,7 +177,11 @@ export function useSendMultipleChatMessage(
|
||||
);
|
||||
|
||||
const handlePressEnter = useCallback(
|
||||
async (...[{ enableThinking }]: NextMessageInputOnPressEnterParameter) => {
|
||||
async (
|
||||
...[
|
||||
{ enableThinking, enableInternet },
|
||||
]: NextMessageInputOnPressEnterParameter
|
||||
) => {
|
||||
if (trim(value) === '') return;
|
||||
const id = uuid();
|
||||
|
||||
@ -214,6 +218,7 @@ export function useSendMultipleChatMessage(
|
||||
files,
|
||||
conversationId: targetConversationId,
|
||||
reasoning: enableThinking,
|
||||
internet: enableInternet,
|
||||
},
|
||||
chatBoxId,
|
||||
currentConversationId: targetConversationId,
|
||||
|
||||
@ -73,6 +73,7 @@ export const useSendSharedMessage = () => {
|
||||
question: message.content,
|
||||
session_id: get(derivedMessages, '0.session_id'),
|
||||
reasoning: message.reasoning,
|
||||
internet: message.internet,
|
||||
});
|
||||
|
||||
if (isCompletionError(res)) {
|
||||
@ -119,7 +120,11 @@ export const useSendSharedMessage = () => {
|
||||
}, [answer, addNewestAnswer]);
|
||||
|
||||
const handlePressEnter = useCallback(
|
||||
(...[{ enableThinking }]: NextMessageInputOnPressEnterParameter) => {
|
||||
(
|
||||
...[
|
||||
{ enableThinking, enableInternet },
|
||||
]: NextMessageInputOnPressEnterParameter
|
||||
) => {
|
||||
if (trim(value) === '') return;
|
||||
const id = uuid();
|
||||
if (done) {
|
||||
@ -135,6 +140,7 @@ export const useSendSharedMessage = () => {
|
||||
id,
|
||||
role: MessageType.User,
|
||||
reasoning: enableThinking,
|
||||
internet: enableInternet,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@ -124,6 +124,7 @@ const ChatContainer = () => {
|
||||
showUploadIcon={false}
|
||||
stopOutputMessage={stopOutputMessage}
|
||||
showReasoning
|
||||
showInternet={chatInfo?.has_tavily_key}
|
||||
></NextMessageInput>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user