### What problem does this PR solve? Feat: Display the thinking process according to the start_to_think flag of the message #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.20.0
| @@ -3,6 +3,7 @@ import { useComposeLlmOptionsByModelTypes } from '@/hooks/llm-hooks'; | |||
| import * as SelectPrimitive from '@radix-ui/react-select'; | |||
| import { forwardRef, memo, useState } from 'react'; | |||
| import { LlmSettingFieldItems } from '../llm-setting-items/next'; | |||
| import { SelectWithSearch } from '../originui/select-with-search'; | |||
| import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'; | |||
| import { Select, SelectTrigger, SelectValue } from '../ui/select'; | |||
| @@ -10,20 +11,28 @@ interface IProps { | |||
| id?: string; | |||
| value?: string; | |||
| onInitialValue?: (value: string, option: any) => void; | |||
| onChange?: (value: string, option: any) => void; | |||
| onChange?: (value: string) => void; | |||
| disabled?: boolean; | |||
| } | |||
| const NextInnerLLMSelect = forwardRef< | |||
| React.ElementRef<typeof SelectPrimitive.Trigger>, | |||
| IProps | |||
| >(({ value, disabled }, ref) => { | |||
| >(({ value, disabled, onChange }, ref) => { | |||
| const [isPopoverOpen, setIsPopoverOpen] = useState(false); | |||
| const modelOptions = useComposeLlmOptionsByModelTypes([ | |||
| LlmModelType.Chat, | |||
| LlmModelType.Image2text, | |||
| ]); | |||
| return ( | |||
| <SelectWithSearch | |||
| options={modelOptions} | |||
| value={value} | |||
| onChange={onChange} | |||
| ></SelectWithSearch> | |||
| ); | |||
| return ( | |||
| <Select disabled={disabled} value={value}> | |||
| <Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}> | |||
| @@ -3,6 +3,7 @@ | |||
| import { CheckIcon, ChevronDownIcon } from 'lucide-react'; | |||
| import { | |||
| Fragment, | |||
| ReactNode, | |||
| forwardRef, | |||
| useCallback, | |||
| useEffect, | |||
| @@ -29,7 +30,7 @@ import { cn } from '@/lib/utils'; | |||
| import { RAGFlowSelectOptionType } from '../ui/select'; | |||
| export type SelectWithSearchFlagOptionType = { | |||
| label: string; | |||
| label: ReactNode; | |||
| value?: string; | |||
| options?: RAGFlowSelectOptionType[]; | |||
| }; | |||
| @@ -109,10 +110,10 @@ export const SelectWithSearch = forwardRef< | |||
| <CommandInput placeholder="Search ..." /> | |||
| <CommandList> | |||
| <CommandEmpty>No data found.</CommandEmpty> | |||
| {options.map((group) => { | |||
| {options.map((group, idx) => { | |||
| if (group.options) { | |||
| return ( | |||
| <Fragment key={group.label}> | |||
| <Fragment key={idx}> | |||
| <CommandGroup heading={group.label}> | |||
| {group.options.map((option) => ( | |||
| <CommandItem | |||
| @@ -42,6 +42,8 @@ export interface IInputData { | |||
| export interface IMessageData { | |||
| content: string; | |||
| start_to_think?: boolean; | |||
| end_to_think?: boolean; | |||
| } | |||
| export interface IMessageEndData { | |||
| @@ -64,9 +64,40 @@ function findMessageFromList(eventList: IEventList) { | |||
| const messageEventList = eventList.filter( | |||
| (x) => x.event === MessageEventType.Message, | |||
| ) as IMessageEvent[]; | |||
| let nextContent = ''; | |||
| let startIndex = -1; | |||
| let endIndex = -1; | |||
| messageEventList.forEach((x, idx) => { | |||
| const { data } = x; | |||
| const { content, start_to_think, end_to_think } = data; | |||
| if (start_to_think === true) { | |||
| nextContent += '<think>' + content; | |||
| startIndex = idx; | |||
| return; | |||
| } | |||
| if (end_to_think === true) { | |||
| endIndex = idx; | |||
| nextContent += content + '</think>'; | |||
| return; | |||
| } | |||
| nextContent += content; | |||
| }); | |||
| const currentIdx = messageEventList.length - 1; | |||
| // Make sure that after start_to_think === true and before end_to_think === true, add a </think> tag at the end. | |||
| if (startIndex >= 0 && startIndex <= currentIdx && endIndex === -1) { | |||
| nextContent += '</think>'; | |||
| } | |||
| return { | |||
| id: eventList[0]?.message_id, | |||
| content: messageEventList.map((x) => x.data.content).join(''), | |||
| content: nextContent, | |||
| }; | |||
| } | |||