import { useMemo, useRef, useState } from 'react'; import type { FlexProps } from '@chakra-ui/react'; import { Box, Button, Flex, Textarea, useDisclosure } from '@chakra-ui/react'; import { HUGGING_FACE_ICON } from '@fastgpt/global/common/system/constants'; import Avatar from '@fastgpt/web/components/common/Avatar'; import MyPopover from '@fastgpt/web/components/common/MyPopover'; import MyIcon from '@fastgpt/web/components/common/Icon'; import MyModal from '@fastgpt/web/components/common/MyModal'; import { useTranslation } from 'next-i18next'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useLocalStorageState } from 'ahooks'; import AIModelSelector from '../../../Select/AIModelSelector'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import { onOptimizePrompt } from '@/web/common/api/fetch'; export type OptimizerPromptProps = { onChangeText: (text: string) => void; defaultPrompt?: string; }; export type OnOptimizePromptProps = { originalPrompt?: string; input: string; model: string; onResult: (result: string) => void; abortController?: AbortController; }; const OptimizerPopover = ({ onChangeText, iconButtonStyle, defaultPrompt }: OptimizerPromptProps & { iconButtonStyle?: FlexProps; }) => { const { t } = useTranslation(); const { llmModelList, defaultModels } = useSystemStore(); const [optimizerInput, setOptimizerInput] = useState(''); const [optimizedResult, setOptimizedResult] = useState(''); const [selectedModel = '', setSelectedModel] = useLocalStorageState( 'prompt-editor-selected-model', { defaultValue: defaultModels.llm?.model || '' } ); const [abortController, setAbortController] = useState(null); const { isOpen: isConfirmOpen, onOpen: onOpenConfirm, onClose: onCloseConfirm } = useDisclosure(); const closePopoverRef = useRef<() => void>(); const modelOptions = useMemo(() => { return llmModelList.map((model) => { // const provider = getModelProvider(model.model) return { label: ( {model.name} ), value: model.model }; }); }, [llmModelList]); const isEmptyOptimizerInput = useMemo(() => { return !optimizerInput.trim(); }, [optimizerInput]); const { runAsync: handleSendOptimization, loading } = useRequest2(async (isAuto?: boolean) => { if (isEmptyOptimizerInput && !isAuto) return; setOptimizedResult(''); setOptimizerInput(''); const controller = new AbortController(); setAbortController(controller); await onOptimizePrompt({ originalPrompt: defaultPrompt, input: optimizerInput, model: selectedModel, onResult: (result: string) => { if (!controller.signal.aborted) { setOptimizedResult((prev) => prev + result); } }, abortController: controller }); setAbortController(null); }); const handleStopRequest = () => { if (abortController) { abortController.abort(); setAbortController(null); } }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey && !e.nativeEvent.isComposing) { e.preventDefault(); if (!loading) { handleSendOptimization(); } } }; return ( <> } trigger="click" placement={'auto'} w="482px" onBackdropClick={() => { if (optimizedResult) { onOpenConfirm(); } else { closePopoverRef.current?.(); } }} > {({ onClose }) => { closePopoverRef.current = onClose; return ( {/* Result */} {optimizedResult && ( {optimizedResult} )} {/* Button */} {!loading && ( <> {!optimizedResult && !!defaultPrompt && ( )} {optimizedResult && ( <> )} )} {modelOptions && modelOptions.length > 0 && ( )} {/* Input */}